Kickstart your Android development journey part II

Clint Paul
10 min readNov 10, 2021
Photo by Danial Igdery on Unsplash

Hi, all.
Let’s start the second part of our Android development journey. If you are here for the first time, check out the first part of this series before starting.

This blog was originally posted at clintpauldev.com

What have we done so far?

So far, we have learned how to create a new Android project in Kotlin, understood the basics of layouts and Activities, manifest files, project structure, build gradle files, resources, etc. Next, we add drawable images to our project, customize our layout according to the design, start working with the activity, etc.

How to add drawables to the project?

Whenever you work with images, do remember this. Android devices come in different screen sizes, and each of these devices can have different pixel sizes. So, instead of using px as the unit for defining the size, Android uses dp ( density-independent pixels ) and sp ( scalable pixels ). If you provide an image with the px as the unit, it will work accurately only on a few devices. Then, the system will try to scale your image in the other devices, which will result in a blurry ‘image.’ To deal with this problem, Android uses different density buckets to store the images. Such as, mdpi, hdpi, xhdpi, xxhdpi, xxxhdpi. For more information, check out this link.

Now, let’s find out a neat icon for our app. Please use any of these sites to find an icon of your liking.

I used this icon,

video_icon

Next, we should convert your selected image to different density buckets. For this, you can use an image generator site like an image baker or app icon generator.

A new folder with the different density buckets will be generated

Now, copy all of these folders. And, right-click on the drawable folder in the Android studio, and click open in -> explorer.

Then, paste those folders you copied earlier to this folder. Now, refresh your drawable folder from the android studio, and you can see that it contains a new folder with your icon and subfolders with the different density buckets.

video_icon folder with the different density buckets

Add the icon to the app

Since we have added our new movie icon, it’s time to add it to our app. Remember where we need to go to change something in the UI? Yes, we must go to our XML file of the appropriate class and make the changes. Open your activity_main.xml and go to the design tab.

Click on the widgets option in the palette and click on the ImageView ( You can also search for the ImageView using the search option in the palette ). Drag the ImageView into the UI, and choose the video icon as the resource and click Ok.

Pick a resource tab

Can you find anything different in the component tree ( Look below the palette tab )? Yes. There is an error showing in our newly added ImageView, right? Hover over it, and read the error description. It says, ‘Missing constraints in the ConstraintLayout.’ Since we are using ConstraintLayouts, we must tie our view with a constraint. Just like we bind a banner on something so that it will not fly away when there is heavy wind or rain? Likewise, there is no guarantee that your view will be in the correct position according to your design if you don’t provide horizontal and vertical constraints.

Error showing because of no constraints

Click on the ImageView, and you will be able to see four circles around it. Use them to constraint your view horizontally and vertically.

How to constraint your view horizontally and vertically

Once you complete this, the error will be gone. Let’s give it some margin_top as well. Remember how did we give the margin earlier? If you don’t remember, now it’s time to play around with the tool and see if you can provide a new margin. ( I have given a margin of 100 dp )

Our icon after giving the margin

Now, can you change the constraints of our TextView? As you can see, now it is constrained horizontally and vertically to the parent. Try to remove the bottom_constraint and change the top_constraint to the bottom of our ImageView. Also, give it some margin_top as well.

Constraint the text view

You can test the changes you have made. Try to change the devices from the device list and change the orientation ( portrait and landscape ). If the ImageView and TextView are not changing their positions differently when selecting different devices, you can verify that it’s working correctly.

Change device size and orientation

Code so far

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:background="@color/cyan_primary_light"
tools:context=".MainActivity">

<TextView
android:id="@+id/textViewSelectedMovie"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:fontFamily="@font/biryani_semibold"
android:text="Godfather"
android:textColor="@color/black"
android:textSize="30sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView2" />

<ImageView
android:id="@+id/imageView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="100dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/video_512_px" />

</androidx.constraintlayout.widget.ConstraintLayout>

Let’s complete the UI

Remember our design? Yes. We still need two buttons and an edit text. Let’s add them now.

Completed app UI

DECIDE MOVIE Button

First, let’s add the “DECIDE MOVIE” button. What’s the first thing to do? Go to your design palette, and grab the button widget to our layout. Try to make the following changes.

  1. Button style: Widget.AppCompat.Button.Borderless
  2. Background color: cyan_primary_dark
  3. Text color: #424242
  4. Text: DECIDE MOVIE
  5. fontFamily: font/biryani_semibold
  6. width: Fill the entire horizontal space

There is one easy way to fill the available space. Be it horizontal or vertical. You can see that there are two options available for the layout_width attribute. wrap_content, and 0dp ( match_constraint ). Change your layout_width to match_constraint, and the button will fill up the entire horizontal space. Please note that the view should be either constrained horizontally or vertically to implement the match_constraint param.

Finally, don’t forget to give an id for your button. Because unless there is a unique ID for your views, there is no way we can use it in our code.

7. id: buttonDecideMovie

Currently, our app will look like this.

App layout after adding the decide button

Code so far

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:background="@color/cyan_primary_light"
tools:context=".MainActivity">

<TextView
android:id="@+id/textViewSelectedMovie"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:fontFamily="@font/biryani_semibold"
android:text="Godfather"
android:textColor="@color/black"
android:textSize="30sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView2" />

<ImageView
android:id="@+id/imageView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="100dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/video_512_px" />

<Button
android:id="@+id/buttonDecideMovie"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@color/cyan_primary_dark"
android:fontFamily="@font/biryani_semibold"
android:text="DECIDE MOVIE"
android:textColor="#424242"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Add new movie EditText

We will use this edit_text to enter new movie names. Grab the Plain Text widget from the palette, and add it to our layout. Try to make the following changes.

  1. Add horizontal constraints to the parent. Give a top_constraint to the bottom of the textViewSelectedMovie.
  2. margin_top: 150dp
  3. hint: Add a new movie ( Delete the text in the text field )
  4. fontFamily: font/biryani_semibold
  5. id: editTextTextAddMovieName

Currently, our app will look like this.

Code so far

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:background="@color/cyan_primary_light"
tools:context=".MainActivity">

<TextView
android:id="@+id/textViewSelectedMovie"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:fontFamily="@font/biryani_semibold"
android:text="Godfather"
android:textColor="@color/black"
android:textSize="30sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView2" />

<ImageView
android:id="@+id/imageView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="100dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/video_512_px" />

<Button
android:id="@+id/buttonDecideMovie"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@color/cyan_primary_dark"
android:fontFamily="@font/biryani_semibold"
android:text="DECIDE MOVIE"
android:textColor="#424242"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />

<EditText
android:id="@+id/editTextTextPersonName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="150dp"
android:ems="10"
android:fontFamily="@font/biryani_semibold"
android:hint="Add new movie..."
android:inputType="textPersonName"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textViewSelectedMovie" />

</androidx.constraintlayout.widget.ConstraintLayout>

ADD MOVIE button

This button will help verify if the user has entered any movies in the edit_text. If then, we can add those movies to our list. Please grab a button from the palette, and add it to our layout. Try to make the following changes.

  1. Add horizontal constraints to the parent. Give a top_constraint to the bottom of the editTextTextAddMovieName.
  2. style: Widget.AppCompat.Button.Borderless
  3. layout_width: match_constraint
  4. margin_top: 16dp
  5. margin_start: 32dp
  6. margin_end: 32dp
  7. background: @color/cyan_primary_dark
  8. fontFamily: @font/biryani_semibold
  9. text: ADD MOVIE
  10. textColor: #424242

Currently, our app will look like this.

Code so far

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:background="@color/cyan_primary_light"
tools:context=".MainActivity">

<TextView
android:id="@+id/textViewSelectedMovie"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:fontFamily="@font/biryani_semibold"
android:text="Godfather"
android:textColor="@color/black"
android:textSize="30sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView2" />

<ImageView
android:id="@+id/imageView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="100dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/video_512_px" />

<Button
android:id="@+id/buttonDecideMovie"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@color/cyan_primary_dark"
android:fontFamily="@font/biryani_semibold"
android:text="DECIDE MOVIE"
android:textColor="#424242"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />

<EditText
android:id="@+id/editTextTextPersonName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="150dp"
android:ems="10"
android:fontFamily="@font/biryani_semibold"
android:hint="Add new movie..."
android:inputType="textPersonName"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textViewSelectedMovie" />

<Button
android:id="@+id/button2"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="32dp"
android:background="@color/cyan_primary_dark"
android:fontFamily="@font/biryani_semibold"
android:text="ADD MOVIE"
android:textColor="#424242"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/editTextTextPersonName" />

</androidx.constraintlayout.widget.ConstraintLayout>

Great job. We have completed the design part. Please feel free to take a five minutes break to have a coffee. You earned it.

Let’s code in Kotlin

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

Most of the time, an Activity will be extending an AppCompatActivity or an Activity. I have explained it in the earlier part. Also, the onCreate() will be the first method that will call when you open an Activity. Here, we will mention the corresponding layout of that Activity. We should refer to activity_main in this case.

Imagine you want to get the reference of the “ADD MOVIE” button in your Activity. Back in the day, we used findViewById() to fetch the view reference in our Activity. But, it created a lot of boilerplate code. Then, after the introduction of Kotlin, Android started using synthetic views. Here, you can directly call the view Id from the Activity to get its reference. Even though we reduced the boilerplate code, now, a new problem occurred. Imagine another view of the same ID present in any other layouts in the project. Kotlin synthetic_views can accidentally point to that view instead of our layout view and result in a crash.

To fix these issues, Android has introduced View Binding. Once enabled in the module, it will generate a binding class for each layout. We can then use this class to find all the views in that layout. It has reduced a lot of boilerplate code, and at the same time, reducing the chances of referring to a view_id in a different layout. For more info, check this link.

Now, let’s enable View Binding in our module. Add this code to the module-level build.gradle file.

android {
...
buildFeatures {
viewBinding = true
}
}

Now, let us create an instance of the binding class.

private lateinit var binding: ActivityMainBinding

Confused about what is the lateinit keyword? As the name suggests, we can initialize the variable after the declaration. It helps us to reduce the unwanted null check. Keep this in mind, if you try to use a lateinit variable before initializing it later, it will throw an exception.

binding = ActivityMainBinding.inflate(layoutInflater)

Call the static inflate() method to create the instance of the binding class for the activity to use.

val view = binding.root

Get a reference to the root view.

setContentView(view)

Finally, pass the root view to the setContentView() to make it active.

Complete code,

class MainActivity : AppCompatActivity() {

private lateinit var binding: ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
}
}

Please run the app and check if everything is working without any crashes. Then, change the text of textViewSelectedMovie to your favorite movie.

binding.textViewSelectedMovie.text = "Inception"

Run the app again and check if the new changes are reflected correctly.

Great job, guys. You did something incredible today. And, I’m happy that I was able to share some of my knowledge with you all. I hope you will try to implement the project yourself. Please depend on this article only as a helping hand. Unless you create a project by yourself and resolve the issues, you will not learn anything.

In the next chapter, we will work with the arrays and learn how to store a list of movies, modify it, and pick one randomly. Please follow me on Linkedin to get my regular Android/Kotlin updates.

You can find the complete project on Github.

--

--

Clint Paul

Software Engineer @ShareChat. I love to read and write.