Android Kotlin Fundamentals 노트 1

2020년 10월 11일

Android Kotlin Fundamentals Course 코드랩 하면서 노트.

Useful Shortcuts

  • Project quick fix: Alt+Enter (Option+Enter on a Mac)
  • Reformat code: Choose Code > Reformat code, or CTRL+ALT+L (Command+Option+L on a Mac)

Vector drawables

A part of Android Jetpack.

As default, android app will contain bitmap version of the drawables in lower than API 21. Vector drawables support in oldver vrsions of Android, back to API 7.

Add this line at defaultConfig in build.gradle (Module:app).

vectorDrawables.useSupportLibrary = true

Click Sync Now button.

Open activity_main.xml layout file and add this namespace at <LinearLayout> tag.


Change android:src in <ImageView> to app:srcCompat.


Note: app namespace is for attributes that come from custom code or libraries.

Use findViewById once

Define member with lateint keyword.

lateinit var diceImage : ImageView

Init the member in onCreate().

diceImage = findViewById(

API Levels

  • compileSdkVersion
  • targetSdkVersion: Usually same as compileSdkVersion
  • minSdkVersion

Architecture of the basic activity template

  • Status bar: Hide the status bar
  • App bar (action bar): Add the app bar
  • App name
  • Options menu overflow button: onOptionsItemSelected() in MainActivity.kt, check res/menu/menu_main.xml
  • CoordinatorLayout ViewGroup: content_main in activity_main.xml
  • Content main
  • Floating action button (FAB): FloatingActionButton in activity_main



Android team

Extract the style

  1. Right-click the component from the component tree and select Refactor > Extract Style.
  2. Fill in the form and save it.
  3. Use named style in activity xml file via style attribute

The style is defined in styles.xml in res.

Changing android:id

When android:id of the component need to be changed, right-click and select Refector > Rename.

Density-independent pixels

Support different pixel densities

Unit conversion: px = dp * (dpi / 160)

Threshold must be needed for dp conversion to pixel. Scale factor is in DisplayMetrics.density.


Optimize your app for autofill

Show/Hide the keyboard

// Hide
val inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)

// Set focus
// Show
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(editText, 0)

Attach onClick events

  • in the XML, add android:onClick attr to the <View> element
  • in the code, use setOnClickListener(View.OnClickListener) function in the Activity


In the activity page, a magnet icon is for Autoconnect feature.

Use Constraint Widget in Attributes section of the activity design page.

the type of the constraint

  • Wrap Content: as much as the element
  • Fixed: Specify a dimension
  • Match Constraints: Expands until meet the constraints on each side


A chain is a group of views that are linked to each other with bidirectional constraints.

Chain styles

set the layout_constraintHorizontal_chainStyle or the layout_constraintVertical_chainStyle.

  • Spread
  • Spread Inside
  • Packed
  • Weighted: layout_constraintHorizontal_weight or layout_constraintVertical_weight

Baseline constraint

The baseline constraint aligns the baseline of a view's text with the baseline of another view's text. Right click on the component and select show baseline.

   app:layout_constraintBaseline_toBaselineOf="@+id/buttonA" />

Design-Time attributes

Only for the layout design. Design-time attributes are prefixed with the tools namespace. e.g. tools:layout_editor_absoluteY, tools:text

Data binding

Eliminate findViewById() using binding objects. Benefits:

  • Code is shorter and easier to read and maintain
  • Resource efficiency
  • Type safety


// build.gradle (Module: app)
android {
  // ...
  buildFeatures {
    dataBinding true
  // ...
// Then sync

Add <layout> at the outermost tag around the layout xml file. Then, move all xml namespaces to the <layout>. e.g.

<layout xmlns:android=""


Add the type of binding in the activity class. For activity_main, the class will be ActivityMainBinding.

private lateinit var binding: ActivityMainBinding

It need to import something like import <your.project>.databinding.ActivityMainBinding.

Then, use DataBindingUtil.setContentView() and remove the previous setContentView().

// import androidx.databinding.DataBindingUtil

binding = DataBindingUtil.setContentView(this, R.layout.activity_main)

Now, the binding object holds all views in the layout.

binding.doneButton.setOnClickListener {}
binding.apply { // kotlinize the function
  nicknameText.text = nicknameEdit.text.toString()
  nicknameEdit.visibility = View.GONE

Data binding to display data

Create the data class in the package.

// MyName.kt
data class MyName(var name: String = "", var nickname: String = "")

Add data to the layout. Open activity xml file and add <data> right under the <layout>. Then, add <variable> tag with name and package path. (package name + variable name)

<layout ...>
      type="" />
  <!-- ... -->

@={} is a directive to get the data that is referenced inside the curly braces. Replace the string like below:

<TextView android:text="@string/name" />
<TextView android:text="@={}" />

Create the data in the activity file.

// MainActivity.kt
private val myName: MyName = MyName("Edward Kim")

Then, binding the object with the view using binding.

// in onCreate()
binding.myName = myName

Manipulate the binding object so that the updated data will reflect to the view.

binding.apply {
  myName?.nickname = nicknameEdit.text.toString()
  invalidateAll() // UI is refreshed with the new value
  // ...

Read more


A Fragment represents a behavior or a protion of user interface in an activity. Modular section of an activity like a "sub-activity".

  • A Fragment has its own lifecycle and receives its own input events
  • You can add or remove a Fragment while the activity is running
  • A Fragment is defined in a Kotlin class
  • A Fragment's UI is defined in an XML layout file

"Inflate the Fragment's view" is equivalant to using setContentView() for an Activity.

class TitleFragment : Fragment() {
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        // create a binding object and inflate the Fragment's view
        val binding = DataBindingUtil.inflate<FragmentTitleBinding>(inflater,
                R.layout.fragment_title, container, false)
        return binding.root

Add the new fragment to the main layout file.

<layout xmlns:android=""




Add dependencies for the navigation library.

// build.gradle (project-level)
ext {
  // ...
  navigationVersion = "2.3.0"
  // ...
// build.gradle (module-level)
dependencies {
  // ...
  implementation "androidx.navigation:navigation-fragment-ktx:$navigationVersion"
  implementation "androidx.navigation:navigation-ui-ktx:$navigationVersion"
  // ...

Sync and rebuild.

Add a navigation graph to the project. right-click the res folder and select New > Android Resource File.

Set navigation as a file name and Navigation as a resource type, then okay.

Open res/navigation/navigation.xml with the navigation editor.

Create the NavHostFragment

NavHostFragment acts as a host for the fragments in a navigation graph.

Open layout xml file and add NavHostFragment like below.

  app:defaultNavHost="true" />

Add fragments to the navigation graph

Open navigation.xml and add new destinations. If the preview is not showing, check tools:layout.

Then drag the dot (circular connection point) on the preview and drop to the destination. Check the ID of the action. (e.g. action_titleFragment_to_gameFragment)

Add the button click event in the Fragment inside the onCreateView() method.

binding.playButton.setOnClickListener { view: View ->

Conditional navigation

Add two fragments to the navigation graph.

Drag the circular connection point to the conditional fragments.

Then, add the code like:

// at onCreateView() in GameFragment.kt
// find the appropriate position...


Change the back button's destination

Control the back stack by setting the "pop" behavior in actions on the navigation editor.

  • popUpTo: back stack to a given destination before navigating.
  • popUpToInclusive
    • false or not set: leaves the specified dest. in the back stack.
    • true: remove all tracing stacks included specified dest.
  • popUpToInclusive=true and popUpTo at app's starting location: all the way out of the app.

Add up button in the App bar

(= action bar)

Designing Back and Up navigation

  • The Up button navigates within the app, based on the hierarchical relationships between screens. The Up button never navigates the user out of the app.
  • The Back button, shown as 2 in the screenshot below, appears in the system navigation bar or as a mechanical button on the device itself, no matter what app is open.

Back button is for the back stack, up button is for the screen hierachy.

Use NavigationUI.

// onCreate() in MainActivity.kt
val navController = this.findNavController(
NavigationUI.setupActionBarWithNavController(this, navController)
// in MainActivity.kt
override fun onSupportNavigateUp(): Boolean {
  val navController = this.findNavController(
  return navController.navigateUp()

Add an options menu

Add new destination to the navigation graph.

Add a options-menu to the project. right-click the res folder and select New > Android Resource File.

Set options_menu as a file name and Menu as a resource type, then okay.

Open options_menu.xml.

Add Menu Item from Plaette to the component tree. Set the id of item to the same name as the target fragment e.g. aboutFragment.

Add onClick handler.

// TitleFragment.kt
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                         savedInstanceState: Bundle?): View? {
  // ...
  setHasOptionsMenu(true) // Add this line
  return binding.root

// Add the options menu and inflate the menu resource file
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
  super.onCreateOptionsMenu(menu, inflater)
  inflater.inflate(, menu)

// Add onOptionsItemSelected() for the navigation
// It uses the id of the selected item
override fun onOptionsItemSelected(item: MenuItem): Boolean {
     return NavigationUI.
            || super.onOptionsItemSelected(item)

Add the navigation drawer

Drawer appears when the user swipes edge to edge or tap the nav drawer button/hamburger icon. It is a part of the material components for Android.

// build.gradle (app-level)
dependencies {
  // ...
  implementation "$supportlibVersion"
  // ...

// then sync!

Add a drawer to the project. right-click the res folder and select New > Android Resource File.

Set navdrawer_menu as a file name and Menu as a resource type, then okay.

Open navdarwer_menu and add menu items. Note: Match the ID for the menu item as for the destination Fragment.

Add <DrawerLayout> and wrap the entire layout in activity xml file. Also, add NavigationView before closing it.

<layout xmlns:android=""

      <!-- ... -->
      app:menu="@menu/navdrawer_menu" />

For swaping, connect the drawer to the navigation controller:

// onCreate() in MainActivity.kt
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(
       this, R.layout.activity_main)

NavigationUI.setupWithNavController(binding.navView, navController)

For drawer button, add the code bleow:

// in MainActivity.kt
private lateinit var drawerLayout: DrawerLayout

// onCreate()
drawerLayout = binding.drawerLayout
NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout)
  // add it as a third param

To make the Up button work with the drawer button:

// onSupportnavigateUp() in MainActivity.kt
override fun onSupportNavigateUp(): Boolean {
  val navController = this.findNavController(
  return NavigationUI.navigateUp(navController, drawerLayout)

다음 챕터: Android Kotlin Fundamentals: 03.3 Start an external Activity