Android Kotlin Developer Nanodegree Projects Review
Tags: android, kotlin, beginners
Published: 2021-12-17 21:02:00

**In this article, I'm going to share my experience in completing Android Kotlin Developer Nanodegree projects.**

As mentioned in my previous article - [Cheated by Android Kotlin Developer Nanodegree Course from Udacity](https://vtsen.hashnode.dev/cheated-by-android-kotlin-developer-nanodegree-course-from-udacity), there are total of 5 projects that you need to complete in order to graduate from the Android Kotlin Developer Nanodegree.  Since I have completed all the projects, I think it may worth for me to share my thoughts on them. 

All the projects come with a starter code. You basically complete these projects on your own based on the guided instructions. The reviewer will pass or fail your project submission based on project rubric (known as project specifications) and also provide feedback on your code. You can submit the projects as many as you want.

> **Note:** I'm going to share my completed code in the following sections. Please use it as your reference only and do not copy my code to graduate from the Nanodegree program! :)

## Course 1 Project: Build a Shoe Store Inventory App

- Starter code: [nd940-android-kotlin-course1-starter](https://github.com/udacity/nd940-android-kotlin-course1-starter)
- Completed code: [vinchamp77/Android_NanoDegree_ShoeStore](https://github.com/vinchamp77/Android_NanoDegree_ShoeStore)

If you follow all the lessons (i.e. Build your First App, Layouts, App Navigation, Activity & Fragment Lifecycle, and App Architecture UI Layer) in this course, you shouldn't have any problem to complete this project. It is pretty straight forward except for listing screen (will be explained later).

There are a total of 5 screens here (i.e. login, welcome, instructions, listing, and detail screens). This is my version of designing the UI. It is up to you how you want to design it. 

![completed_android_kotlin_developer_nanodegree_projects_01.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1637538630451/xD8sqTydg.gif)

The login screen is just a placeholder. It doesn't really function as an actual login screen. The purpose of this project is to demonstrate that you know how to navigate from one fragment to another.

### What I learned?

- **ViewModel** and **Live Data** (observe live data and setup click listener)
- **Single Activity Architecture** (implement multiple fragments and navigate between them with transition animation)
- **SafeArgs** (pass data between fragment using bundle)
- **Layout Design** with **sytles.xml** (use `ConstraintLayout` and standardize the design style across different layouts)
- **Data binding** in layouts (implement both 1-way and 2-way data binding - e.g. in `EditView`)
- **ScrollView** (dynamically insert item into `ScrollView` during runtime)
- **Logout Menu** (implement menu at the top left corner of the phone)

### What I struggled? 

**Dynamic ScrollView**

The hardest part in the project is the listing screen where you need to implement the `ScrollView` which has `LinearLayout` as child. Then, you need to manually insert the `TextView` into the `LinearLayout`.  It is hard because it is not taught before in the lessons. I need to google this a bit to figure this out.

This is an example of `ScrollView` + `LinearLayout` in the layout xml:

```xml
<!-- scroll view and linear layout are used so to that it supports more shoe listings -->
<ScrollView
    android:id="@+id/scrollView"
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:layout_constraintBottom_toTopOf="@+id/add_shoe_button"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent">

    <LinearLayout
        android:id="@+id/shoe_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" />
</ScrollView>
```
I also created `item_shoe.xml` layout to allow me easily to inflate the layout so I did not need to create the `TextView` manually in code.

This is how my `item_shoe.xml` looks like:
```xml
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/textView"
    style="@style/DefaultTitle"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
```

In the code, I inflate the `item_shoe.xml` layout, update the text and add `textView` into the `LinearLayout`.

```kotlin
private fun addShoe(shoeName: String) {
    val view = layoutInflater.inflate(R.layout.item_shoe, null)
    view.textView.text = shoeName
    binding.shoeList.addView(view.textView)
}
```

This is how I implemented the listing screen. It can be done in different way. Please also note that using `RecycleView` (which will be learned in next project) is more practical than `ScrollView`.


## Course 2 Project: Build an Asteroid Radar
- Starter code: [nd940-android-kotlin-c2-starter](https://github.com/udacity/nd940-android-kotlin-c2-starter/tree/master/starter)
- Completed code: [vinchamp77/Android_NanoDegree_AsteroidRadar](https://github.com/vinchamp77/Android_NanoDegree_AsteroidRadar)

Lessons in this course is probably the most useful and practical one in my opinion. The lessons include App Architecture (Persistence), `RecycleView`, Connect to the Internet, Behind the Scenes, and Designing for Everyone. 

![completed_android_kotlin_developer_nanodegree_projects_02.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1637538242897/uyPXwNjQc.gif)

### What I learned?
- **RecycleView** (display list of asteroids)
- **Retrofit** (download data from internet)
- **Moshi** (convert JSON data to usable class data)
- **Picasso** (download and cache images)
- **BindingAdapter**(implement custom attribute in layout xml)
- **Room Database** (implement offline caching)
- **Work Manager**(schedule to update database every day)
- **Accessibility** (provide basic accessibility such as content description for texts and images)

### What I struggled?

**Parse JSON Data**

The starter code provided the `parseAsteroidsJsonResult()` function, but it did not explain why this is needed. This is because the `Moshi` library is unable to convert the JSON data to the class data due to the received JSON format complexity.

So, the `Retrofit` service API needs to return `String` instead of `List<Asteroid>`. Then, I convert the `String` to JSON object using `JSONObject()`.  After that, I pass the JSON object to this helper function `parseAsteroidsJsonResult()` to convert it to `List<Asteroid>`. 

See example below:

```kotlin
suspend fun getAsteroids() : List<Asteroid> {
    val responseStr = retrofitService.getAsteroids("","", NetworkConstants.API_KEY)
    val responseJsonObject = JSONObject(responseStr)

    return parseAsteroidsJsonResult(responseJsonObject)
}
```

**Issue with Glide?**

The project mentioned `Glide` has issue downloading the image, but it did NOT explain why. Thus, `Picasso` is used in the starter code

So, I tried to replace `Picasso`
```kotlin
Picasso.with(imageView.context)
    .load(it.url)
    .into(imageView)
```

with `Glide`
```kotlin
Glide.with(imageView.context)
    .load(it.url)
    .into(imageView)
```
and everything still worked as expected. So, I do not really understand why. I guess it is likely the issue is no longer valid anymore?

Honestly, I wish they explain why and gives more detailed information.

> Tip: By the way for the Asteroid API, you don't need request an API key. You can use the `DEMO_KEY` directly and commit it directly to `GitHub` (which okay since this for demonstration purpose).

### What will I do next?
This is the useful feedback that I get from the reviewer.
> You can now also use the [KotlinX Serialization library](https://github.com/Kotlin/kotlinx.serialization) which is in the stable release. 
This library supports JSON deserializing without Reflection based lookups and hence can save a lot of memory and time for large projects and also supports MultiPlatform.
The syntax is fairly easy but very powerful when deserializing large JSON.

So this is going to be my to-do list to understand how this library works.

***[Updated - Aug 06, 2022]:*** *I finally tried KotlinX Serialization but the result is NOT impressive at all. The claim it saves memory and time is simply NOT true. See my following article:*

- [Simple REST API Android App in Kotlin - Various HTTP Client Library Implementations](https://vtsen.hashnode.dev/simple-rest-api-android-app-in-kotlin-various-http-client-library-implementations)

## Course 3 Project: Design an App with Application Loading Status 
- Starter code: [nd940-c3-advanced-android-programming-project-starter](https://github.com/udacity/nd940-c3-advanced-android-programming-project-starter)
- Completed code: [vinchamp77/Android_NanoDegree_CustomAppLoadingStatus](https://github.com/vinchamp77/Android_NanoDegree_CustomAppLoadingStatus)

This course is all about notification and custom animation. The lessons include Using Notification, Creating Custom Views, Drawing on Canvas Objects, Clipping Canvas Objects,  Android Property Animations, and Using `MotionLayout` to Animate Android Apps.

This is how the app looks like:

![completed_android_kotlin_developer_nanodegree_projects_03.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1637547659107/RQ2suW956.gif)

### What I learned?
- **Custom View** (create custom view / button by inheriting `View`)
- **Custom Attributes** (create custom attributes using `withStyledAttributes()`)
- **ValueAnimator** (use `ValueAnimator` and `Paint` to perform animations)
- **Canvas** (use `paint` to draw the `Canvas` UI)
- **MotionLayout** (use `MotionLayout` and `MotionScene` to perform animation)
- **Notification** (send notification and use `pendingIntent` to create the notification action)

### What I struggled?
What I struggled is to make this learning stick. Maybe this the least used feature and I do not have chance to practice it? So, I write down some notes here for my future reference.

**How to use ValueAnimator?**

- Create a `ValueAnimator` - define returned value and duration
```kotlin
 private val valueAnimator = ValueAnimator.ofInt(0, 360).setDuration(2000)
``` 
- Set up the animation callbacks - `progress` is the callback value which is used to perform drawing animation
```kotlin
valueAnimator.apply {
    addUpdateListener {
        progress = it.animatedValue as Int
        invalidate()
    }
    repeatCount = ValueAnimator.INFINITE
    repeatMode = ValueAnimator.RESTART
}
```
- Override `onDraw()` - use `progress` and `paint` to draw the canvas.
```kotlin
override fun onDraw(canvas: Canvas?) {
    super.onDraw(canvas)

    // loading button
    paint.color = buttonLoadingColor
    canvas?.drawRect(0f, 0f, widthSize * progress/360f, heightSize.toFloat(), paint)
} 
```

**How to start MotionLayout without user interaction?**

The course shows you how to trigger the animation but it doesn't show you how to runs the animation automatically.  So I added this `app:autoTransition="animateToEnd"` in my `MotionScene` file to auto start the animation when fragment is created.
```xml
<Transition
    app:constraintSetStart="@+id/start"
    app:constraintSetEnd="@+id/end"
    app:duration="3000"
    app:autoTransition="animateToEnd">
</Transition>
```

**Include layout is used**

The `<include>` tag is used in all the layout xml files in the starter code which I wasn't really familiar with since this is not taught in the course too. However, it is not a big deal to understand it.

For example, you can see this in `activity_main.xml` file:
```xml
<include layout="@layout/content_main" />
```

### What will I do next?
Animation is my weak area but I probably won't focus in this area now. There are too many higher priority things to learn in the Android development.

## Course 4 Project: Build a Location Reminder App

- Starter code: [nd940-android-kotlin-c4-starter](https://github.com/udacity/nd940-android-kotlin-c4-starter)
- Completed code: [vinchamp77/Android_NanoDegree_Location_Reminders](https://github.com/vinchamp77/Android_NanoDegree_Location_Reminders)

> **Note:** Please read the [README.md](https://github.com/vinchamp77/Android_NanoDegree_Location_Reminders/tree/master#readme) in the completed code. You need to setup the API Keys in order to run the app.

This is the worst project because the starter code has bunch of compilation errors. I attempted to fix but failed. I ended up just use the version provided by one of the mentors in the knowledge forum.

The lessons in this course include Wandering in Goolge Maps with Kotlin, Virtual Treasure Hunt with Geofences, Testing Basic, Intro to Test Double and Dependency Injection, Testing: Survey of Advanced Topics, and Implementing Login on Android with FirebaseUI.

This project use almost all the things that I learned in these lessons.

![completed_android_kotlin_developer_nanodegree_projects_04.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1637567793692/NbE3ntiPy.gif)


### What I learned?
- **Firebase** (setup Firebase project, register app with Firebase,  add sign-in provider for authentication, download `google-services.json` to `app` folder directory)
- **Google Map** (enable Maps SDK for Android in Google Cloud Platform API & Services, setup API usage restriction to my app only, add `SupportMapFragment` in layout xml, implement `OnMapReadyCallback` interface) 
- **Map Features** (show current location, add marker, add POI, implement custom map style - `map_style.json`)
- **GeoFences** (add geofencing request)
- **Location Permission** (request `ACCESS_FINE_LOCATION` permission)
- **Device Location** (auto resolve device location if disabled)
- **Unit Test** (test `ViewModel` with fake data source)
- **Instrumentation Test** (use Espresso and Mockito to test the app UI and Fragments Navigation)
   1. **Expresso** - library to interact with UI and check UI state
   2. **Mockito**  - library to check whether method is called
- **Koin** (use `Koin` to inject dependencies into repository)

### What I struggled?

**Only My Location Layer is needed to show Current Location?**

In theory, device location is not required to be enabled to show the current location in Google Map. Only the [My Location Layer](https://developers.google.com/maps/documentation/android-sdk/location#the_my_location_layer) needs to be enabled to do that. 

I'm not able verify this scenario. In my emulator, the current location will be shown correctly only if I enable the device location.  If I disable the device location, it doesn't work.

So, I posted the question to the mentor in the Udacity knowledge forum and he ran fine with my code in his emulator. So, I have no ideas why? 

One thing I don't understand is when you try to run a "Google Map" in your phone, it does explicitly require user to enable device location.  Maybe device location is needed after all? 

**Koin Dependency Injection**

The test code uses `Koin` but the course doesn't teach you anything about `Koin`. The course only teaches you constructor depedency injection. To be honest, I tried to study the code and I did not 100% understand it. 

### What will I do next?

**Custom Login Screen**

Instead of the default login screens of FirebaseUI, we can customize them. I will need to learn how to customize it. The resource [here](https://github.com/firebase/FirebaseUI-Android/blob/master/auth/README.md#custom-layout) is for my reference.

**RequestPermission Contract**

There are 2 ways to request permission. We can either manage the request code ourselves or use the [RequestPermission contract](https://developer.android.com/training/permissions/requesting#allow-system-manage-request-code) (allow the system to manage the permission request code for you). The current code manages the request code ourselves.

Because using the RequestPermission contract simplifies the logic, it's recommended that we use it when possible. So I gave this a try, I implemented this RequestPermission Contract already in my Final Capstone project and it worked great!

**Hilt & Dagger Depedency Injection**

I am totaly not familar in this area. Instead of `Koin` (it seems a bit harder to understand), I will try to understand Hilt & Dagger first since there is pretty well official documentation [here](https://developer.android.com/training/dependency-injection/hilt-android#hilt-and-dagger). 

***[Updated - Feb 06, 2022]:*** I have tried Hilt and documented the steps to implement it here.*

- [How to Implement Hilt in Android App?](https://vtsen.hashnode.dev/how-to-implement-hilt-in-android-app)

## Final Capstone Project: Design and Build an Android Application

- Starter code: [nd940-cap-advanced-android-programming-project-starter](https://github.com/udacity/nd940-cap-advanced-android-programming-project-starter/tree/master/starter)
- Completed code: [vinchamp77/USElectionInfo](https://github.com/vinchamp77/USElectionInfo)

> **Note:** Please read the [README.md](https://github.com/vinchamp77/USElectionInfo#readme) in the completed code. It requires you to setup the API Key  in order to run the app.

This is the final capstone project. You have 2 options. First option is implement a custom app. If you choose this option, you need to submit a design document. Second option is implement a Political Preparedness app.

I chose second option - **Political Preparedness** app. I renamed the app to **US Election Info**.

![completed_android_kotlin_developer_nanodegree_projects_05.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1637636197783/QUhO3GhQL.gif)

### What I learned?
What I learned here are pretty much have already been covered in the previous courses. So there isn't any thing new here.

- **Fragment Navigation** (implement navigate graph, implement `Parcelable` object with `@Parcelize` annotation to pass data between fragments)
- **MVVM Architecture** (implement clean architecture using Repository acting as Model entry)
- **Motion Layout** (hide the form while dragging up the `RecycleView`)
- **Retrofit** (connect to and consume data from a remote data source such as a RESTful API)
- **Glide** (load network resources, such as Bitmap Images, dynamically and on-demand)
- **Room Database** (store data locally on the device for use between application sessions and/or offline use)
- **Location** (request location permission and resolve device location setting if it is turned off)

***\[Updated - Apr 30, 2023\]:*** *For MVVM architecture, you can refer to the following article.*

- [MVC vs MVP vs MVVM Design Patterns](https://vtsen.hashnode.dev/mvc-vs-mvp-vs-mvvm-design-patterns)

### What I struggled?

**Code does Not Compile**

The code doesn't compile and has many errors. I found troublesome to fix them. So I decided to **build the app from scratch** and use the starter code as a reference. 

In fact, this helped me a lot to understand the project. For example, I figured out mininum SDK 24 is required because of `@color` resource reference in `ballot_logo.xml` (which is only supported in SDK 24 and above).  The starter code uses minimum SDK 26 which is technically unnecessary. It can be lower down to SDK 24.

I also reorganized the package / folder structure based on my own recommendation in my previous article - [How to organize android package folder structure?](https://vtsen.hashnode.dev/how-to-organize-android-package-folder-structure) 

So, my folder / package structure looks like this:

![completed_android_kotlin_developer_nanodegree_projects_06.JPG](https://cdn.hashnode.com/res/hashnode/image/upload/v1637638161079/ZRfhX_rH5.jpeg)

**Motion Layout does NOT really work as Intended**

When dragging up the `RecycleView`, the form supposes to drag up too like the following and vice-versa.

![completed_android_kotlin_developer_nanodegree_projects_07.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1637644826252/x7iNBKPf-.gif)

However, I took the short cut to just simply hide the form.

![completed_android_kotlin_developer_nanodegree_projects_08.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1637644983004/tOWDPyrb6.gif)

This is how I did in in the motion scene file (simplified version) by using `android:visibility="gone"` attribute at the end `ConstraintSet` 
```xml
<?xml version="1.0" encoding="utf-8"?>  
<MotionScene      
    xmlns:android="http://schemas.android.com/apk/res/android"  
    xmlns:app="http://schemas.android.com/apk/res-auto">  

    <ConstraintSet android:id="@+id/start">  
        <Constraint android:id="@id/search_title" />  
    </ConstraintSet>
      
    <ConstraintSet android:id="@+id/end">  
        <Constraint  android:id="@id/search_title"  
        android:visibility="gone" />    
    </ConstraintSet> 
     
    <Transition  
        app:constraintSetStart="@id/start"  
        app:constraintSetEnd="@id/end">  
    
        <OnSwipe  app:dragDirection="dragUp"  
           app:touchAnchorId="@id/representatives_recycler_view" />     
    </Transition>  
    
</MotionScene>
```

### What will I do next?
I want to publish this app in Google Play store. In fact, I have already done it.  You can check it out [here](https://play.google.com/store/apps/details?id=com.androidcafe.uselectioninfo)!

***[Updated - Jan 15, 2021]:*** *I faced the app rejection issue (i.e. missing clear source of information) while I tried to publish. Here is what I needed to do to fix it.*

- [How to Resolve Missing Clear Source of Information - Disclaimer App Rejection?](https://vtsen.hashnode.dev/how-to-resolve-missing-clear-source-of-information-disclaimer-app-rejection)

## Career Service

Once you have completed the 5 projects, you have one extracurricular, which consists of these 2 projects:
- Take 30 Minutes to Improve your LinkedIn
- Optimize Your GitHub Profile

There are some lessons in these 2 projects. At the end of the project, you're going to submit your LinkedIn / GitHub profile to the reviewer for feedback. You don't need to resubmit them. One submission is considered passed.

These projects are optional but you need to manually opt out. I gave it a try, and I'm going to share my views on them. 

> Most of the stuff here is common sense.  So, I'm going to share what is new to me or something that I can improve on?

### Take 30 Minutes to Improve your LinkedIn

**What I learned?**

- Use present tense for current duties, past tense for prior duties and accomplishments. What I have before is all present tenses.
-  There is a project section on LinkedIn, which I wasn't aware previously. You need to manually add them into your profile.

**What will I do next?**

- Fix wording to include the correct tense.
- Update project section with [my Android development projects](https://vtsen.hashnode.dev/projects)
- Reduce my skills section and put the most relevant one and use optimized keywords. I have too many of them which are not applicable anymore. 

> Feedback that I get from my reviewer is not very valuable because most of the stuff is pretty generic or already been covered in the lessons. What I learned above is mainly part of the course content. I did not learn any extra from the reviewer.

### Optimize Your GitHub Profile

**What I learned?**

- Having a great README is important. I probably knew this already but haven't got chance to improve it.
- Commit graph that shows as many as green squares significant. Example of good commit graph:
![completed_android_kotlin_developer_nanodegree_projects_09.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637705723882/gTClgy9PC.png)

**What will I do next?**

- Improve README in my GitHub, enroll to this free course from Udacity: [Writting READMEs](https://classroom.udacity.com/courses/ud777)
- Collaborate with others and contribution to open source - I'm not  sure if I can do this. It seems a bit hard. However, this definitely will be my goal. 

> The reviewer gave me a lot of feedback. He even read my article in this blog and provided his opinion.  A lot of resources have been shared by him and these resources are not part of the lesson which is good. 

## My Final Thoughts
- The issue with all these started code projects is the code and libraries are outdated. So what I did the first thing, is updating the started code to use the latest libraries and fix all the warnings. It is basically all the update recommendations by Android Studio.

> I managed to do this for all projects except for course 4 project. It has too many legacy codes which makes the upgrade almost impossible. You can try that, but it is going to waste your time.

- I commit my initial working version into `GitHub` using Android Studio. If you don't know how to do this, you can refer to [How to update Android Studio project to GitHub?](https://vtsen.hashnode.dev/how-to-upload-android-studio-project-to-github) 
- I always perform incremental commit for every successful run. This way when things go wrong, I can always rollback to my previous working version.
- My suggestion is, don't look at the solution or completed code and work on the starter code directly. Then, you compare your solution with mine or other students. This way you learn more and make your knowledge stick!
- If you get stuck, ask the mentor (if you enroll in this program).
- Overall, the projects provided by Android Kotlin Developer Nanodegree are well-structured. 
- However, the course is quite expensive. Whether it is worth it or not, it is up to you. You can check out my article - [Is it Worth to Pay for Android Kotlin Developer Nanodegree?](https://vtsen.hashnode.dev/is-it-worth-to-pay-for-android-kotlin-developer-nanodegree)

**I hope this review is useful.**

---

*Originally published at [https://vtsen.hashnode.dev](https://vtsen.hashnode.dev/android-kotlin-developer-nanodegree-projects-review)*.