This past weekend I finally took the plunge and updated my Android TV / Fire TV application to use ExoPlayer. Yeah, I’m a bit behind the curve here, and should have done this a while ago. When I first wrote Serenity for Android about 5 years ago, you pretty much had to roll your own Player UI if you wanted anything more than the bare basics. Thankfully, things are much simpler with ExoPlayer and the provided SimpleExoplayerView. Everything I had to roll by hand and brute force implement in MediaController and the SurfaceView are now bundled directly in the SimpleExoplayerView. This includes the ability to display Subtitles. What took me about a good 2 months to implement myself, was basically done in a couple of days with Exoplayer.
The other nice thing about Exoplayer is that it brings video playback stability across devices. Using the old player and MiBox Android TV device, if I tried to play back a movie with Dolby Digital Audio it would crash the app. With ExoPlayer it works directly out of the box with the basic configuration. This was the main reason that I made the switch to ExoPlayer. The other reason is the ability to support Transcoding and choose either HLS or Dash support. Currently Serenity supports the Universal Transcoder from the latest Plex Servers, but will hopefully start supporting the Emby Media Server as well.
While we are talking about Plex… why haven’t they provided 3rd party developers with a real documented API yet? Emby has a complete Java API as well as APIs for multiple other languages. Plex makes it so you have to reverse engineer what they are doing, or hope you can decipher one of the few remaining Open Source clients they have available to use and browse the code. It is one of the reasons I’m starting the migration to Emby instead of Plex. Functionality wise they are about equal now, but the open source nature of Emby fits better with my goals. Having a documented API will help foster your third party developers, which can help drive users to possibly look at some of your paid subscription options for your applications.
Back to Exoplayer, I highly recommend taking a look at the library if you haven’t already. If your last experience creating a video player or audio player was with the old Android APIs, then you will be presently surprised what you get out of the box for free now with ExoPlayer.
Now on to Kotlin. It has been the rage for a while now in the Android community, especially with Google adopting it as an official supported language for Android development now. Kotlin has a lot of good things too it, but along with the good comes some very frustrating things.
- Increase in method count size. If you have an app that needs to run on older devices still and you are near the 64K method limit. You can be pushed over the edge with Kotlin and will need to start using Multi Dex. One of the issues (features) is that Kotlin generates property accessors (getter/setters) for all field level variables you define that aren’t private. This means that you can needlessly have extra methods generated that are never used.
- If you do Test Drive Development or just write Unit Tests for your application (you do do this right???). Then you will run into how much of a pain that Kotlin’s close by default nature becomes. A work around for this is to use the Kotlin All Open plugin, to make classes and functions annotated with a particular annotation open by default. This allows mocking frameworks like Mockito to play better with Kotlin generated code. I understand the reasoning and I think closed by default is perfectly valid for Data classes within Kotlin, I just don’t agree that everything should be closed by default for all classes.
- If you have a Java Interface that you need to implement in a Kotlin, and that interface has getter and setters defined. You will not be able to use a Data class for this implementation. The reason being you need to override the default definitions of the getter and setters within Kotlin. So you loose the conciseness that Data classes provide.
- There are pain points still if your application is a Hybrid application (i.e. a mix of Java and Kotlin code). Accessing singleton instances from within Java code that was written in Kotlin can be a pain due to having to access inner Companion classes.
- Dependency Injection is a bit funky with Kotlin if you use Dagger. Because Dagger requires at least protected or internal fields and these fields can’t be private. You’ll end up with a lot of getters and settters in the generated code. Plus, you will need to use lateinit var option on your fields that will be injected. If you need to annotate a field with more than one annotation you will need to use the really funky @field:[Inject ForVideoQueue] annotation format, where the options in the @field annotation are the multiple Annotations to be assigned to the field. The added levels of syntax sugar can make the underlying code more verbose.
- Becareful with the use of the null (?) operator in Kotlin, it can generate a bunch of extra code that you normally wouldn’t see generated as it checks for Null every time the method is used. This can affect your code coverage results if you aren’t careful.
Kotlin isn’t all frustrating though. It does force you to really do some defensive programming, and with some refactoring of existing code and knowing the flow of your application, use of @NonNull annotations in your Java Code can help detect possible NPE’s and keep you from passing these to Kotlin code. Also the short cuts for one line methods is nice as well for reducing some boiler plate code.
I’m still early in my Kotlin adoption, but I see why people like it, but as much as people talk it up as the greatest thing since sliced bread, it still has it’s warts just like any other language.