Building A Shazam Clone Part 5 (Discover Song Feature) — Building Android Apps Series

In the last post, we walked through test-driven development on Android and wrote a UI test that checks if the discover view is visible to the user.

In this post, we will be working on the discover page still using the test-driven process. Unfortunately, there won’t be a tutorial video for this post. To cover up for this, I tried to simplify the code as much as possible and added lots of ( redundant) comments.

To begin, let’s update the layout for the DiscoverFragment we created in the previous post. We want to create a design that looks like the photo below.

Open the fragment_discover layout and copy the layout code below into it (There are just 6 Views in the layout and I added some explanatory comments above each).

Note: We made use of ConstraintLayout, if you are not familiar with it you can use this ConstraintLayout CodeLab to get started.

There are a few resources that need to be created to get the layout working properly. First is the circular background for the start and stop ImageButtons. Create a new drawable file called bg_circle_white.xml in the res/drawable folder of the project and copy the content below into it.

Second is the required string resources used mostly as the content description for the ImageButtons. Android apps should be usable by everyone, including people with disabilities. This post does a great job at explaining why adding a content description for images is important. Update the strings.xml file in the res/values folder with the content below.

Lastly, we need to include the icons for the:

  • Start & stop ImageButton (ic_mic_gray_24dp)

We will be using vector drawables rather than the regular PNG files. I created the vector drawables easily using the Vector Asset Studio. If you are not familiar with the tool, we will just manually copy the generated vector content into the respective files here.

First, create a new drawable file called ic_mic_gray_24dp.xml in the res/drawable folder and copy the content below into it.

You can ignore all the weird looking numbers and letters, except you are interested in learning more about vectors. Create another drawable file called ic_favorite_white_24dp.xml and copy the code below into it.

Lastly, create a drawable file called ic_history_white_24dp.xml and copy the code below into it.

To support vector drawable on devices running platform versions lower than Android 5.0 (API level 21), we will need to configure the app to use vector support libraries. Add the vectorDrawables element to the build.gradle file in the app module like this:

After all the work, you should be able to preview your layout in the design tab (of the layout editor) and it should look very similar to the screenshot above.

With the discover layout completed, let’s start implementing the discover feature. As usual, we will start by writing tests first.

We will create a quick UI test for the DiscoverFragment that tests the following buttons:

  • The start button

Create a new Kotlin class file called DiscoverFragmentTest in the androidTest folder (use the photo below as a guide).

Copy the code below into the DiscoverFragmentTest file (I have included comments for each line to explain what it does)

In the DiscoverFragmentTest above, we made use of some View ids we have not defined yet. So lets quickly create them and their corresponding Activities before trying to run our test. First, we will need to create the following new packages for the different activities:

  • songdetail

Next, let’s create the needed Activities one at a time.

1. Create a new empty Activity called SongDetailActivity in the newly created songdetail package

Update the activity_song_detail layout that was generated when the Activity was created with the content below.

2. Create another new empty activity called HistoryActivity in the history package:

Also, update its layout file (activity_history) with the content below.

3. Finally, create a new empty activity called DonateActivity in the donate package:

Update the Activity generated layout file (activity_donate) with the layout code below.

We have added all the required view ids and can now run the DiscoverFragmentTest by clicking on the green play button at the top when the test file is open.

It should fail because there is no implementation yet or no code to handle the button presses.

We can now start adding some implementation. Like I said in part 2, we will be using the MVP architecture (You might also want to check MVVM). Our implementation of MVP will be similar to the Google architecture blueprint MVP app.

We will start out by creating two base interfaces that every View and Presenter will implement.

Create a new Kotlin interface called BaseView and copy the code below into it (Every view in this project will implement this interface).

We will do the same for presenters, create a BasePresenter Kotlin interface and copy the code below into it (Every presenter in the project will implement this interface).

Like I said in part 2, we will define all the interactions between the view and the presenter in a single contract interface. Create a new interface called DiscoverContract in the discover package and copy the code below into it.

With the discover presenter contract defined, we can go ahead to create a presenter for the discover page. Create a new class called DiscoverPresenter in the discover package. For now, the method body will be empty as we will have to write a test first before writing the implementation.

Again we will follow the TDD mantra when working with the DiscoverPresenter. We will write test first, then the implementation later. Unlike the previous tests we have written so far, the test for the presenter will be in src/test folder.

src/test is for pure unit test that do not involve android framework. You can run tests here without running on a real device or on emulator. On recent versions of Android Studio you should be able to see it like this.

You will need to create a discover package in the test folder. Then create a DiscoverPresenterTest inside of the discover package. I tried to really simplify the test code and added explanatory comments in between codes. Copy the code below into the created DiscoverPresenterTest class

We are referencing a class and interface we haven’t written yet and if you try to run the test above, you will get a compilation error. We will need to create the Song class and the SongIdentifyService .

  1. To create the Song class, first create a new package called data.identify. Then create the Song class inside of this package

2. The SongIdentifyService will be responsible for music identification and will call a callback functions when an error occurs or when a song is successfully identified. For now we will define the interface, in the later parts we will create a concrete service that identifies songs.

Create a new package called data.identify. Inside of the package, create a new Kotlin interface called SongIdentifyService. Copy the code below into it.

We can now run the DiscoverPresenterTest.

As usual, the test should fail because we haven’t added the DiscoverPresenter implementation yet.

In the next part of this series, we will be adding the DiscoverPresenter and DiscoverFragment implementation. Stay tuned.

If you enjoyed this story, please click the 👏 button and share to help others find it! Also feel free to leave a comment below.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store