Migrating to Kotlin at Chirp.

Dinu Chiriac
Chirp
Published in
5 min readOct 26, 2018

--

At Chirp we love new technologies. As Kotlin is the fastest growing language we decided to move forward and start experimenting with Kotlin in our Android SDK. In this article, we are going to show you a couple of examples where Kotlin creates cleaner, more elegant code and makes your life easier as a developer.

One of the most critical components of our SDK is our Audio I/O module — it does two things: grab the audio buffer from the microphone and send it to the engine to be processed; and send the processed audio buffer from the engine to the speaker when we are sending data.

From the first lines of code written in Kotlin, we realised that the code looks tidy and it is much easier to read thanks to lambda expressions.

Lambda expressions in Kotlin

Lambda expressions in Kotlin are a type of functions that are not declared but passed immediately as an expression. Making an analogy with javascript, a lambda expression is just a callback function passed as an argument. Callbacks are very helpful when you are working with events like “do this when something happens”. For example, a quite common callback in android is OnClickListener for buttons. Here is how you normally have to implement the OnClickListener in Java.

/* Java */
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
/* the callback body */
}
});

This becomes quite frustrating when you have a lot of buttons in your activity and for each one, you have to implement different callbacks. In other words, why repeat yourself?

/* Kotlin */
button.setOnClickListener { /* the callback body */ }

Doesn’t this look great? We’ll not go in details about how Kotlin is doing this as there are enough articles about that but in brief, the setOnClickListener method already defines the arguments it accepts, so you don’t need to define it again, just pass a lambda function instead which in the end will be converted to a new OnClickListener during the compilation time.

Threads in Kotlin

We are not using buttons in our audio library, however, we are using threads quite a lot. The reason for this is that Audio needs to be consistent and every minor delay in processing audio can be critical. Let’s take a look at how Threads can be implemented in Java vs Kotlin.

/* Java */
Thread outAudioThread = new Thread(new Runnable() {
public void run() {
/* Implementation here */
Thread.currentThread().interrupt();
}
});
outAudioThread.start();

And here is how you can create a thread in Kotlin.

/* Kotlin */
thread
(start = true, priority = THREAD_PRIORITY_URGENT_AUDIO) {
/* Implementation here */
Thread.currentThread().interrupt()
}

Isn’t this better? Sure, and again, as you can see, there is no new Runnable defined here, Kotlin will do this for you.

Instance instantiation in Kotlin

Now, going further, as we said, our audio library is used to pass audio buffers between the microphone, speaker and chirp engine. In order to do this in our Java version, we implemented an interface class which instance you have to pass as an argument when the Audio class is instantiated.

/* Java callback interface*/
public interface ChirpAudioBufferCallback {
byte[] processOutput(byte[] buffer);
void processInput(byte[] buffer);
}

And here is a cut of ChirpAudio class implemented in Java

/* ChirpAudio Java class*/
public class ChirpAudio {
....
public void startOutAudioLoop() {
Thread outAudioThread = new Thread(new Runnable() {
public void run() {
android.os.Process.setThreadPriority(THREAD_PRIORITY_URGENT_AUDIO);
while (isRunning) {
outBytes = audioBufferCallback.processOutput(outBytes);
audioPlayer.write(outBytes, 0, OUT_BUFFER_SIZE);
}
Thread.currentThread().interrupt();
}
});
outAudioThread.start();
}
public void setAudioBufferCallback(ChirpAudioBufferCallback audioBufferCallback) {
this.audioBufferCallback = audioBufferCallback;
}
....
}

Next, in order to instantiate our ChirpAudio class we have to instantiate ChirpAudioBufferCallback interface first then we’ll be able to set it to ChirpAudio instance with setAudioBufferCallbacksetter.

/* Instantiate and use ChirpAudio class in Java */
ChirpAudioBufferCallback audioBufferCallback = new ChirpAudioBufferCallback() {

@Override
public byte[] processOutput(byte[] buffer) {
/* process buffer then return it to be played */
return buffer;
}

@Override
public void processInput(byte[] buffer) {
/* process input buffer from the mic */
}

};
ChirpAudio audio = new ChirpAudio();
audio.setAudioBufferCallback(audioBufferCallback);

How this can be done in Kotlin? First, we don’t really need to create the ChirpAudioBufferCallback Interface for callbacks, we can pass them directly with lambdas. Second, because we removed the callback interface, the instantiation is much cleaner as well.

/* ChirpAudio in Kotlin */
class ChirpAudio {
....
fun startOutAudioLoop(outAudioCallback: (buffer: ByteArray?) -> ByteArray?) {
thread(start = true, priority = THREAD_PRIORITY_URGENT_AUDIO) {
while (isRunning) {
outBytes = outAudioCallback(outBytes)
if (outBytes !== null) {
audioTrack.write(outBytes, 0, OUT_BUFFER_SIZE)
}
}
Thread.currentThread().interrupt()
}
}
....
}

And here is how to instantiate the new ChirpAudio class and startAudioLoop

/* Instantiate and use ChirpAudio class in Kotlin */
val audio = ChirpAudio()
audio.startOutAudioLoop {
/* process buffer then return it to be played */
return@startOutAudioLoop buffer //lambda qualified return
}

Just this, nothing more, just create the instance and pass the callback function as a lambda and we are done 🎉.

Overall, the number of lines in our complete ChirpAudio implementation was shrunk from ~270 lines to less than 100 lines of code — almost 3 times less code and clearer syntax.

This is the first experience with Kotlin we had I can confidently say that this is the feature of mobile development. I’m certain that sooner or later it will replace Java boilerplate and that this is a good thing.

However, taking in consideration that Kotlin gives you so many features, it can be very easy to write a badly designed code so you must be careful with that.

Another thing that surprised me is how easy is to write unit tests. Thanks to Mockk testing library you don’t have any issues with mocking static methods while Spek framework makes unit tests look beautiful — but this is for another blog post.

In conclusion, according to stackoverflow, Kotlin became the second most loved language in 2018 and I bet will become the first most loved language in 2019 and to contribute to this, here is another ❤️ from me.

--

--