Home Android & Kotlin Books Android Apprentice

20
Networking Written by Tom Blankenship

Heads up... You're reading this book for free, with parts of this chapter shown beyond this point as scrambled text.

You can unlock the rest of this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

In this section, you’re going to utilize many of the skills you’ve already learned and dive into some more advanced areas of Android development. You’ll build a full-featured podcast manager and player app named PodPlay. This app will allow searching and subscribing to podcasts from iTunes and provide a playback interface with speed controls.

The following new topics are covered:

  • Android networking.
  • Retrofit REST API library.
  • XML Parsing.
  • Search activity.
  • MediaPlayer library.

Getting started

PodPlay will contain these main features:

  1. Quick searching of podcasts by keyword or name.

  1. Display for previewing podcast episodes.

  1. Playback of audio and video podcasts.

  1. Subscribing to your favorite podcasts.

  1. Playback at various speeds.

Project set up

You’ll start by creating a project with a single empty Activity. This app uses the same structure as PlaceBook, but it will also add a new services layer.

Where are the podcasts?

Before you get to the fun part of podcast playback, you need to answer a fundamental question: Where do podcasts come from? The answer is just about anywhere. Podcasts are distributed using a standard format called RSS (Rich Site Summary, commonly referred to as Really Simple Syndication).

Android networking

So far, all of the apps you’ve built during your apprenticeship have been self-contained. They have not had to access any remote or network-based services directly. Although PlaceBook did access Google Places and download place photos, that was all handled by the Places library. That’s about to change with PodPlay.

PodPlay architecture

Continuing with the layered architecture, you’ll create a service layer that handles all network access to iTunes and hides the details of that communication. This will make it easy to swap out different methods for network access, without affecting any other parts of the code.

iTunes search service

If you regularly listen to or have ever created a podcast, you’re probably familiar with the iTunes podcast directory. This provides a single place to find almost any podcast from a variety of categories.

Retrofit

Now that you know how to get search results, the next step is to turn them into data models.

Defining Retrofit dependencies

First, you need to define the Retrofit dependency.

ext {
  kotlin_version = '1.3.61'
  retrofit_version = '2.7.1'
}
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
compileOptions {
  sourceCompatibility = 1.8
  targetCompatibility = 1.8
}
kotlinOptions {
  jvmTarget = JavaVersion.VERSION_1_8.toString()
}

Creating the podcast response model

Now you’ll create the model that represents a response from the iTunes service.

data class PodcastResponse(
    val resultCount: Int,
    val results: List<ItunesPodcast>) {

  data class ItunesPodcast(
      val collectionCensoredName: String,
      val feedUrl: String,
      val artworkUrl30: String,
      val releaseDate: String
  )
}
interface ItunesService {
  // 1
  @GET("/search?media=podcast")
  // 2
  fun searchPodcastByTerm(@Query("term") term: String):
      Call<PodcastResponse>
  // 3
  companion object {
    // 4
    val instance: ItunesService by lazy {
      // 5
      val retrofit = Retrofit.Builder()
          .baseUrl("https://itunes.apple.com")
          .addConverterFactory(GsonConverterFactory.create())
          .build()
      // 6
      retrofit.create<ItunesService>(ItunesService::class.java)
    }
  }
}
// 1
class ItunesRepo(private val itunesService: ItunesService) {
  // 2
  fun searchByTerm(term: String,
      callBack: (List<ItunesPodcast>?) -> Unit) {
    // 3
    val podcastCall = itunesService.searchPodcastByTerm(term)
    // 4
    podcastCall.enqueue(object : Callback<PodcastResponse> {    
      // 5
      override fun onFailure(call: Call<PodcastResponse>?,
          t: Throwable?) {
        // 6
        callBack(null)
      }
      // 7
      override fun onResponse(
          call: Call<PodcastResponse>?,
          response: Response<PodcastResponse>?) {
        // 8
        val body = response?.body()
        // 9
        callBack(body?.results)
      }
    })
  }
}
val TAG = javaClass.simpleName

val itunesService = ItunesService.instance

val itunesRepo = ItunesRepo(itunesService)

itunesRepo.searchByTerm("Android Developer") {
  Log.i(TAG, "Results = $it")
}
<uses-permission android:name="android.permission.INTERNET"/>
I/PodcastActivity: Results = [ItunesPodcast(collectionCensoredName=Fragmented - Android Developer Podcast, feedUrl=https://rss.simplecast.com/podcasts/1684/rss, artworkUrl30=http://is5.mzstatic.com/image/thumb/Music62/v4/4a/6f/e7/4a6fe7c8-7ca1-c43f-241d-f7e84a014f1b/source/30x30bb.jpg, releaseDate=2017-09-18T05:00:00Z), ItunesPodcast(collectionCensoredName=Android Developers Backstage, feedUrl=http://feeds.feedburner.com/blogspot/AndroidDevelopersBackstage, artworkUrl30=http://is3.mzstatic.com/image/thumb/Music62/v4/15/c9/96/15c996fd-4856-79bb-12ba-1d25c67d77d7/source/30x30bb.jpg, releaseDate=2017-09-11T17:20:00Z), ItunesPodcast(collectionCensoredName=The Android Cast, feedUrl=http://www.buzzsprout.com/60878.rss, artworkUrl30=http://is1.mzstatic.com/image/thumb/Music71/v4/8d/b5/4c/8db54c53-75c0-b214-9606-a228e19f49f9/source/30x30bb.jpg, releaseDate=2016-10-08T07:00:00Z)]

Where to go from here?

The term dependency injection was mentioned briefly when you created the iTunesRepo class. You used a simple form of dependency injection when you passed in the ItunesService instance to the iTunesRepo constructor.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.

Have feedback to share about the online reading experience? If you have feedback about the UI, UX, highlighting, or other features of our online readers, you can send them to the design team with the form below:

© 2021 Razeware LLC

You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

Unlock Now

To highlight or take notes, you’ll need to own this book in a subscription or purchased by itself.