Categories
android blog kotlin

Building a podcast app series: 5. Dependency injection

Koin to the rescue

I am a big fan of dependency injection, I think no matter how small or big your application is, some sort of dependency injection is a must. Luckily there are multiple options to choose from when it comes to DI frameworks and my personal favorite is Koin.

If you are new to Koin or dependency injection, please check out my other blog series on Koin here.

In the context of our podcast app, Koin is responsible for creating and maintaining a single instance of ExoPlayer among other things, in fact, every object that we create and need to share its instance we will utilize Koin.

So how does Koin provide our ExoPlayer instance across the app? We will create an instance of ExoPlayer and wrap it around a single {} keyword (which is basically an infix extension function).

  single<ExoPlayer> {
    SimpleExoPlayer.Builder(androidContext()).build().apply {
            setAudioAttributes(
                AudioAttributes.Builder().setContentType(C.CONTENT_TYPE_MUSIC)
                    .setUsage(C.USAGE_MEDIA).build(), true
            )
            setHandleAudioBecomingNoisy(true)
        }
    }

single is a special Koin function that will make sure we are always injecting the same ExoPlayer instance in our app.

Now to inject this ExoPlayer instance we can use Kon’s inject or get extension methods to use lazy or eager injection. Here is the link to two Koin module files where we create all dependencies of our podcast app

With this its time to finish up our Building a podcast app blog series, I’ll see you again soon :).

Categories
android blog kotlin

Building a podcast app series: 4. Player service

How do we make sure that our app can run in the background and play a podcast without worrying about Android shutting the app down to claim resources? A foreground service to the rescue!

MediaBrowserServiceCompat

What the heck is a MediaBrowserServiceCompat? It’s a service that ExoPlayer ships with, and it can simplify the task of creating a background service for the player. Since Android O, any service that wants to be alive for extended periods of time should also show a notification and mark itself as a foreground service. To accomplish this we need to make use of PlayerNotificationManager class, also shipped with ExoPlayer, that given a media session token for our player will display a notification which will be in sync with the ExoPlayer. This is the most complicated part of the whole ExoPlayer setup because it works with a variety of Android APIs, and we all know how easy is it to use Android APIs.

PlayerNotificationManager

In order to utilize PlayerNotificationManager class, we need to create an instance of it and pass in a context, notification channel id, notification id, and a MediaDescriptionAdapter. The MediaDescriptionAdapter is how we tell the PlayerNotificationManager what is the title and image resource for our currently playing episode. Once we create an instance of this class, we can customize it in various ways. The most important method call after we create an instance is setPlayer(exoPlayerInstance). This is super important, given an ExoPlayer instance, PlayerNotificationManager will listen to that ExoPlayer instance changes and change the notification UI accordingly. This is a simple configuration of the PlayerNotificationManager

val playerNotificationManager = PlayerNotificationManager(context, channelId, notificationId, adapter)
playerNotificationManager.setPlayer(exoPlayer)
playerNotificationManager.setMediaSessionToken(it)

This leaves us with a question, who will supply an ExoPlayer instance? There can be a singleton that always returns a single instance, or even better, dependency injection can be used to provide the ExoPlyaer instance to different classes. That is what we will focus on the next, and it will be the last article in the series.

Notification channels

One thing we can do in this player service is to create a notification channel that PlayerNotificationManager will use to actually show a notification. Here is a simple way to create a new channel in case it is not created. Android O requires channels to be created before notifications can be presented to the user. We want to set the priority to low here to avoid any sounds or vibrations coming from the player notification when the user presses any action. Let’s look at an example

    private fun shouldCreateNowPlayingChannel(notificationManager: NotificationManagerCompat) =
        Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !nowPlayingChannelExists(
            notificationManager
        )

    @RequiresApi(Build.VERSION_CODES.O)
    private fun nowPlayingChannelExists(notificationManager: NotificationManagerCompat) =
        notificationManager.getNotificationChannel(nowPlayingChannelId) != null

    @RequiresApi(Build.VERSION_CODES.O)
    private fun createNowPlayingChannel(notificationManager: NotificationManagerCompat) {
        val notificationChannel = NotificationChannel(
            nowPlayingChannelId,
            getString(R.string.notification_channel),
            NotificationManager.IMPORTANCE_LOW
        ).apply {
           description = getString(R.string.notification_channel_description)
        }
         notificationManager.createNotificationChannel(notificationChannel)
    }

Checkout this Github link for the full player service code.

Stay tuned for the next article where we will explore a simple yet powerful dependency injection framework called Koin (technically it is a service locator but it enough to what we need for this app)

Categories
android blog kotlin

Building a podcast app series: 3. Exoplayer

What is a podcast app if not a wrapper around a media player? And, if we talk Android, there is the only one media player worth considering, ExoPlayer, made by Google engineers. Let’s look at how can we connect all the pieces we have built so far and actually connect the ExoPlayer with the view within the app.

ExoPlayer

Exoplayer is very powerful and modular, we are going to use just a fraction of what ExoPlayer really offers. ExoPlayer has a couple of core components that have to work together for it to play anything, in no particular order:

  1. ExoPlayer instance
  2. MediaSource

We need to create an ExoPlayer instance and hold it in memory since it is pretty expensive to create. We will reuse a single instance throughout the app. For it to play anything, we need to create a MediaSource. These sources are basically different types of streams that ExoPlayer has to read in order to fetch the audio data and play it. There are other important parts to the ExoPlayer ecosystem but for starters, we need those two basic things.

ExoPlayer instance

This is the heart of ExoPlayer and the object itself. We can simply create a single instance and pass or not pass a bunch of configuration options. Let’s keep it simple and create a basic instance:

val player = SimpleExoPlayer.Builder(context).build()

MediaSource

So the name of this class is pretty self-explanatory, we have to be aware of the fact that there are a couple of different media sources, depending on the actual source that serves the content:

  • DashMediaSource for DASH.
  • SsMediaSource for SmoothStreaming.
  • HlsMediaSource for HLS.
  • ProgressiveMediaSource for regular media files.

Let’s create a simple media source:

val mediaSource =
   ProgressiveMediaSource.Factory(dataSourceFactory).
        createMediaSource(Uri.parse(it.mp3Url))        
  exoPlayer.prepare(mediaSources)

And that’s it. We can now play an episode!

Since we are building a podcast player, it is safe to assume we will never play one episode at a time, so we need a way to tell ExoPlayer to play the next item when one item is finished playing. To handle that, ExoPlayer has a concept of the concatenated media source. We can bundle together a bunch of media sources, they don’t have to be of the same type, and attach that source to the ExoPlayer instance.

val mediaSources = (listOf(currentEpisode) + _playlist).map {
   ProgressiveMediaSource.Factory(dataSourceFactory).
        createMediaSource(Uri.parse(it.mp3Url))        
   }.toTypedArray()
exoPlayer.prepare(ConcatenatingMediaSource(*mediaSources)

So instead of passing just one media source, we can pass in a concatenating media source and the ExoPlayer will automatically play all episodes from that playlist.

Browse the full code on this link and in the next article, we will talk about a foreground service that needs to run our ExoPlayer and keep our app in the background so Android does not shut down our app to claim more resources :).

Categories
android architecture blog kotlin

Building a podcast app series: 2. Player state

After the view is set up, it’s very important to have a model that will drive that UI, something that we can observe and render our UI according to its state. It would be nice to react to model changes with some kind of a listener and it would be great if we don’t have to manually subscribe/unsubscribe to this model. Luckily, Android has a ViewModel class that is built for this exact purpose.

ViewModel

View modes are a relatively new invention. Before ViewModels came along, and the whole AAC (android architecture components), representing ViewModels in a clean and safe way was particularly tricky. Android activity or a fragment can be in multiple states and properly connecting/disconnecting a particular activity or a fragment is a dance around onCreate / onDestrory, onResume / onPause, and other lifecycle methods. Since our in-app player view is visible on all screens, wee need a globally accessible state holder for that player. Luckily, a ViewModel is all we need to safely share the player state across different fragments. Since we are using a single activity pattern, ViewModels are automatically tied to that activity and can be shared across fragments! This means that we can easily tell other views what is the state of our in-app player by just sharing a ViewModel across multiple fragments! Oh, by the way, ViewModels survive configuration change, so that is also being taken care of.

So, how do we create a new view model? We can simply write in any fragment

private val playerViewModel by sharedViewModel<PlayerViewModel>()

The basic idea here is that ViewModels do not care who is using its LiveData, it can be a single fragment or bunch of them, it does not matter. ViewModels should not reference any Fragment or Activity, they simply expose data for Views to observe!

If you are curious about the code for the PlayerViewModel check out this link.

LiveData

Once we have a shared state holder for our player, we need a safe way to update our views. That is where LiveData comes in, it is a safe container for any kind of data. And the best part about LiveData is that it automatically knows if our fragment or activity is active and can receive updates, so we don’t have to handle that logic ourselves! This means no more null pointer exceptions of illegal state exceptions. We are free to post new data to LiveData and be sure that nothing will crash as a result of that.

How do we create and update live data?

private val _currentlyPlaying = MutableLiveData<Episode>()
currentlyPlaying.value = currentEpisode

Repository pattern

The last piece of the state puzzle is to identify where does our data come from? In a simple word: from a Repository of Podcasts! Repository pattern is such a simple pattern and very useful. We can make our Repository do a bunch of interesting things. We can cache data to the local DB, we can mock our data, we can fetch something from the internet, everything related to data and its retrieval is hidden behind our Repository class.

How does a simple repository look like?

class PodcastRepository {
    fun getPodcasts(): List<Podcast> =
        listOf(Podcast("The Joe Rogan experience"))
}

Basic setup for every screen

In conclusion, every screen in our app will reference ViewModels and will subscribe to LiveDatas. ViewModels will fetch data from Repositories and update LiveDatas and we have a reactive setup for each screen in our app. Error handling is done in the same manner, we just have a LiveData of error messages where we can push errors and observe them inside Fragments.

Browse the full code on this link. Stay tuned for the next article in this series where we explore exoPlyaer, brains behind any podcast app.

Categories
android blog kotlin

Building a podcast app series: 1. mini in-app player

I am currently working on a project to rewrite an existing podcast app that was originally built with xamarin into a fully native Android app. The most important feature of any podcast app is the player, and specifically, the in-app player that has to:

  1. be visible on all screens
  2. have collapsed and expanded view

Let’s clarify the second point, the in-app player should have two modes, collapsed mode where the player’s view is small and should sit below the main content. The second mode is expanded mode, where the player’s view should occupy the whole screen. Ideally, there should be an animation when the player is transitioning between those two states. Let’s talk about solving problem number 1.

Navigation library

If we use the navigation library and single activity pattern from AAC (android architecture components), we can easily make our in-app player visible on all screens by restricting the navigation host fragment to be above the in-app player’s view. Since the navigation framework loads / unloads all views inside the navigation host fragment, we can make all views in our app span just up to the in-app player. If the player is hidden, all views automatically span over it, otherwise, they will span to just above the player.

A nice side effect of using the single activity pattern is the player itself will be configured from one place, main activity, and in combination with a view model, we can implement the player without violating the DRY principle. Now let’s talk about implementing the second feature.

Layout behavior

Ever since the coordinator layout came out, Android became a lot more flexible in terms of animations and interaction between views. In this specific use case all I had to do was to write a normal constraint layout and add one line to it:

<androidx.constraintlayout.widget.ConstraintLayout
....
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">

That was enough to have a view that can sit on the bottom of the screen, be expanded and animate those state changes out of the box. Pretty awesome if you ask me. So, how does the final layout look like?

<CoordinatorLayout>
   <MainContent/>
   <InAppPlayer/>
</CoordinatorLayout>

Of course, nothing is this simple, is it? :). But, what if our app has tabs and a BottomNavigationView? Our in-app player should, of course, sit above the BottomNavigationView but below the main content. One solution to this edge case is to position the main content above the bottom tabs’ view using constraint layout.

DRY principle and ViewModel

Since the player exists across multiple screens (fragments), we need a view model to group together all the player features in one place and just reuse the view model across all views. What better way to implement this than to use AAC ViewModel class. We can easily share this view model across fragments and have a player UI in sync at all times. PlayerViewModel can get data from a PodcastRepository class which will make network calls or read from the local database.

Please refer to this GitHub link for the code.

Stay tuned for the next article in this series!

Categories
android blog koin kotlin

Koin and arguments injection

In previous articles, we explored the basics of Koin. In this article let’s look at more advanced uses of Koin, in particular how to provide constructor dependencies.

Let’s say that we have a details view which needs a presenter, that presenter, in turn, needs an item id which can be used to request item details from the backend. In Koin, we can just provide a lambda with an argument instead of our dependency directly, for example:

class Presenter(val id : Long)
    val myModule = module {
         single { (id : Long) -> Presenter(id) }
    }

Now in our view (activity/fragment), we can just inject the presenter like this

val id = getIdFromArguments()
val presenter : Presenter by inject { parametersOf(id) }

What if we want to resolve a dependency directly in a Koin module for a particular class? We can use get() to eagerly load our dependency, for example:

val dataModule = module {
    single { UserSession() }
    single { UserRepository(get()) }
}
class UserRepository(private val userSession: UserSession)

In the example above UserRepository class depends on UserSession class and we can provide UserSession instance by simply writing get() which will walk our dependency graph in Koin and grab an instance of UserSession().

Now, can you spot a problem with the way we provide constructor arguments for UserRepository class? What will happen when we change the constructor for UserRepository class? The code above won’t compile! Why? Because we need to write another get() for the second argument, for example:

val dataModule = module {
    single { LocalStorage() }
    single { UserSession() }
    single { UserRepository(get(), get()) }
}
class UserRepository(private val userSession: UserSession,
                     private val localStorage: LocalStorage)

And this is the downside of Koin and the runtime dependency injection, Dagger can automatically write wiring for the new constructor during compile time, and we don’t have to modify anything. Fortunately this is a compile-time error and we will be warned by the Android studio promptly.

Stay tuned for the next article!

Categories
android blog koin kotlin

Koin and three ways to define a component (single, factory and scoped)

To continue where we left off in the last article, we will talk about Koin and different ways dependencies can be declared.

Singles

I use single the most when I declare my dependencies. It just means that there will be only one instance created for the entire app. Each injection will use the same instance. This is useful for repositories and long-living objects in the app. In a module, we can define a singleton this way

val myModule = module {
    // declare Service as single instance
    single { Service() }
    single { Controller(get()) }
}

Factory

In contrast to single, factory will create a new instance each time the component is injected, and this is useful when we inject presenters in the MVP architecture, or when we inject something that should be unique to the caller. To give an example:

class Controller()
val myModule = module {
    // declare factory instance for Controller class
    factory { Controller() }
}

Scoped

This is where Koin can shine. Imagine we need to keep our instances living a bit longer, so we can’t use factory but we also don’t want a singleton, so we can’t use single to create our dependencies. This is where scopes come in, we will tell Koin when we want to create a scope and from that moment on, all dependencies will live as long as the scope lives. This is useful when we want to have an auth scope and a non-auth scope to recreate our instances when a user logs in and logs out. This can help us reset our dependencies and provide new ones when the user state is changed. Think of a Retrofit instance, and how we have to inject the user token when the user is logged in so we need a new retrofit instance for that.

If anyone tried to set up scopes in Dagger they know how complicated and painful that can be. With Koin, it’s nothing like that, let’s look at an example

module {
    scope("scopeId"){
        scoped { Presenter() }
        // ...
    }
}

Here we just create a scope by name of scopeId and we can use that id to create and destroy that scope and all of its dependencies. We create our scope with this function

val scope = koin.createScope("myScope")

After we are done with this scope we can call

scope.close()

What? That easy? Of course, its Koin, we can do magic in just a few lines of code :).

Stay tuned for the next article in this series!

Categories
android blog koin kotlin

Using Koin for dependency management in Android apps

So I have been using Dagger2 in previous apps and I was quite ok with it. But I always felt that Dagger may be an overkill for small apps and even medium apps. So when I started working on a new Android app I decided to look for alternative ways to manage my code dependencies. I had a couple of ideas on what I need:

  • Good integration with the Android ecosystem
  • Easy to understand for new team members
  • Good performance

I heard about Koin quite some time ago so I thought this is the perfect opportunity to try it out. I did have one issue with Koin, give that it resolves dependencies during the run time I was worried about the performance a bit. So I tried to find some benchmarks and luckily I found what I was looking for in this blog post! Koin 2.x had a huge performance upgrade compared to Koin 1.x, almost a 10x improvement. For 400 dependencies it takes Koin 2.x around 10 ms to walk up the dependency graph and inject required dependencies which is more than enough for my current project.

Now comes the fun part, how easy is it to setup Koin on a new project? I have to be honest here, it took me no more than 20 minutes to get the basics of Koin and have a couple of dependencies injected in my activities. I was blown away by how simple Koin is. There are three basic concepts in Koin

  • Modules
  • Injection
  • Module list

Lets quickly explain each concept.

Modules

Similar to Dagger, Koin uses a module to group actual instances you will inject. So in my app, I have ServiceModule (dependencies for a background service), PresentationModule (android ViewModels) and DataModule (various repositories)

val myModule : Module = applicationContext {
    // ViewModel instance of MyViewModel
    // get() will resolve Repository instance
    viewModel { MyViewModel(get()) }
    // Single instance of Repository
    single<repository> { MyRepository() }
}

Injection

After instances are being provided in the modules there is a special inject() method that can inject those dependencies into Activities, ViewModels or Repositories. To give an example:

class MyActivity : AppCompatActivity(){
    // Inject MyPresenter
    val presenter : MyPresenter by inject()
    override fun onCreate() {
        super.onCreate()
        // or directly retrieve instance
        val presenter : MyPresenter = get()
    }
}

Module list

Before everything is tied up together, Koin needs to be started and all modules have to be connected so that Koin can start connecting them together. This is done with a special startKoin function that lives in the application class.

 startKoin {
            // use AndroidLogger as Koin Logger - default Level.INFO
            androidLogger()
            // use the Android context given there
            androidContext(this@MainApplication)
            // module list
            modules(serviceModule, presentationModule, dataModule)
        }

And that is basically it. In the next couple of articles, we will dig a bit deeper into some nuances that Koin has in store for us and how I solved some problems with injection in my current android project.

Stay tuned!

Categories
algorithms EPICh6 kotlin

Problem 6.4 from EPI -> Advance through an array

This problem is quite interesting, at first I thought the only solution to this is using recursion or some sort of graph traversal algorithm. But the problem is much simpler than that if you think about it, we don’t care for all possible paths, we just wan to know if end is reachable. So an easier way is to just keep the maximum index we can reach, and check at the end if we reached last index. How to calculate the next maximum index? nodeMax = i + A[i]. Check out the solution here.

Categories
algorithms EPICh6 kotlin

Problem 6.2 from EPI -> Increment an arbitrary precision decimal number

This one is very cool, what if you have to implement a plus one operation to a very large number, in most languages you have that like in Java there is a BigInteger, but what if you have to write it in c++? Then you would implement your own addition, so the problem requires to implement +1 operations, which can be easily transformed into two number addition, check out the solution here.
I have also added a solution for the variation of problem 6.2. The variation requires addition of two strings that contain binary representation of two numbers. The solution is not that difficult, there is this hard coded version and a more elegant version with bitwise operations, check out the solution here.