Category: kotlin

Lessons Learnt with Kotlin: Extension Functions

Lessons Learnt with Kotlin: Extension Functions

At Over, we’ve been using Kotlin since we started the new Android version of the app in November 2018. From day one, we’ve been excited to try the language features and leverage them to build our mobile design app.

One of the features we were most excited about was extension functions.

What is an Extension Function?

An extension function allows you to extend a classes functionality without needing to edit (or have access to) the class itself. They are great for libraries whose classes you can’t access. 

This is an example of an extension function in Kotlin: 

fun Canvas.center(): Point = Point(width / 2f, height / 2f)

You can then use it wherever required, as if that function formed part of the Canvas class itself, although it is not explicitly part of the API: 

val centerPoint = canvas.center()

How we overused them:

When we first started writing Kotlin, we were eager to use the new functionality of the language. We wanted to use extension functions and we didn’t realise the consequences of over-using them. We ended up with a code base that used them everywhere

The main functionality of the app (i.e. the rendering of projects), was written with extension functions. Want to render an image to the screen? Extension function. Want to render some text to the screen? Extension function. Want to do anything that doesn’t quite fit into the MVVM/MVP/MVI model? Extension function. 

This got tricky when we needed to start doing background loading and caching. Where should that logic and state be kept if everything is just an extension function? 🤨

It was at this point that we realised we had overused extension functions. Instead of creating new classes and concepts, we had created extension functions. 

This meant we needed to do a large refactor of the rendering to remove extension functions and rather create a new class to perform this related functionality.  

Disclaimer

This is not a blog post stating that “extension functions are terrible! don’t use them!”. They are an extremely useful feature of the language and we still use them at Over. We are just a bit more careful about what we use them for and where

We don’t do this ❌

We don’t use extension functions for non-related methods. For instance, this example below should not form part of the String API. It is unrelated functionality to the String class and shouldn’t be provided as an extension on that class since its specific to our business logic.  

fun String.toUserProperties() : UserProperties {
return UserProperties(this.toUppercase())
}

In this case, we would rather not make the extension function at all and just use the constructor of the UserProperties class to get this functionality. 

One thing to remember is that this function will be made available to your entire project (if you don’t make it private), which is also a great reason not to make an extension function. 

We do this ✅

We add extension functions onto classes when it makes sense to do so and the function relates to the class that we are extending.

For example, this method can totally be a part of the String API since it is related to String manipulation and it is commonly used throughout our app:

fun String.toGraphemeCharsList(): List<String> {
// do something to get list of grapheme characters
}

Side note: For those who are unfamiliar with the word grapheme . A grapheme is the smallest unit of a writing system. In Java/Kotlin, calling the loved String.toCharArray() method, will return characters in their unicode form. So if you are working with emoji or special characters, they are generally made up of more than one unicode character. For instance, the following emoji: 👩‍👩‍👧 is actually a combination of multiple emojis (as well as multiple unicode characters), so String.toCharArray() returns the “incorrect” number of visible characters on screen, it returns the number of unicode characters. Read more about this here.

However, we favor creating new classes for new behaviour, instead of adding extension functions onto existing classes.

We use extension functions on classes that aren’t extendable (i.e. classes that are part of the framework or primitives). We also create private extensions and use them only in the file they were created.

Summary 📃

Extension functions are a powerful feature in Kotlin that can be overused if you are not careful about when and where you use them. We made that mistake early on and now we are a lot more aware of our usages of them. 

Hopefully this article helps you reason about extension functions, when you are considering using them in your code. 

Have any thoughts or questions? Find me on Twitter.

Over ❤️ Kotlin – How we’ve used Kotlin to build our design app

Over ❤️ Kotlin – How we’ve used Kotlin to build our design app

I recently presented this talk at Kotlin Everywhere South Africa as the keynote for the event. I really enjoyed preparing this talk as it spoke about how we use Kotlin, mistakes we’ve made along the way and our opinion on how we decide to use certain features. 

Talk Description:

Over the past year and a half, I’ve worked primarily on a Kotlin codebase. We at Over, were lucky enough to get a chance to start a project from scratch and we chose Kotlin for many reasons. Our app has been featured multiple times on the Google Play Store and we have found ourselves facing some unique challenges with the product.

In this talk, I’ll cover what my experience has been like working on a Kotlin codebase. I will cover some of the features in Kotlin we use the most, some features we eagerly over used and some of the mistakes we’ve made along the way.

The video recording can be found here: 

The slides for the talk can be found here:

Android Canvas APIs with Kotlin and KTX

Android Canvas APIs with Kotlin and KTX

Learn how to use the Android KTX extension functions to clean up Canvas drawing code

Have you ever wanted to write a Custom View on Android but you were too afraid to deal with X, Y translations on a Canvas object? 

Well, working with them got a whole lot easier when using Kotlin and the Android KTX Extension functions provided by the Android Team at Google. 

Drawing on Canvas without KTX 🙀🙅🏽‍♀️

If you want to translate (move) an object you are drawing on a Canvas, how would you go about doing that? You would likely need to do something like the following:

canvas.save()
canvas.translate(200f, 300f)
canvas.drawCircle(...) // drawn on the translated canvas
canvas.restore()

Canvas#save() and Canvas#restore() can be used to save() the current matrix (transformations like translate, rotate etc) and restore() the state of the Canvas back to its original transformations. 

The drawCircle() method that we are calling will be drawn at a translated point on the Canvas. Once restore is called, the Canvas is no longer translated and any further operations on that Canvas after that point will not be translated.

Example of a circle being drawn to a Canvas, the first doesn’t contain a translation, whereas the second has a translation applied

If we wanted to then do something more complex, for instance, draw a path that is scaled up after we have translated, the code would look as follows:

val translateCheckpoint = canvas.save()
canvas.translate(200f, 300f)
canvas.drawCircle(...) // drawn on the translated canvas
val rotateCheckpoint = canvas.save()
canvas.rotate(45f)
canvas.drawRect(...) // drawn on the translated and rotated canvas
canvas.restoreToCount(rotateCheckpoint)
canvas.restoreToCount(translateCheckpoint)
Example of drawing a Rect — Image 1: No transformations — without doing save/restore. Image 2: Translated with same checkpoint as circle. Image 3: Translated and rotated.

To do multiple translations on a Canvas, we would then want to use restoreToCount with the specific checkpoint. This will notify the canvas of the certain checkpoint of the transformations that should be restored. 

We can see that this can easily get out of control and it becomes really difficult to follow what transformations will be applied to a certain draw... call.  

Improving Canvas API calls with Android KTX 😻

To use these extension functions, you need to make sure you are importing the core-ktx dependency in your app level build.gradle file (look here for the latest version):

implementation 'androidx.core:core-ktx:1.0.1'

If we are using KTX, we can simplify the previous draw examples to be the following:

canvas.withTranslate(200f, 300f) {
drawCircle(...)
}

This wraps up this logic in a block, that makes it easier to understand and our code is cleanly separated. We also don’t need to specify the canvas on which to draw on at this point, since the block now has the Canvas in this scope. If we wished to draw certain parts of the Canvas at different points, say we wanted to translate and scale, we can nest the withRotate function inside the first withTranslate block. 

canvas.withTranslate(200f, 300f) {
drawCircle(...) // drawn on the translated canvas
withRotate(45f) {
drawRect(...) // drawn on the translated and rotated canvas
}
}

Now our function calls are clearly separated with parentheses and we can easily see which canvas transformations will be applied to the drawRect function by using these extension functions. 

Diving into the Android KTX implementation 📝

This is one of the extension functions for Canvas defined in the KTX library (original source code can be found here):

/**
* Wrap the specified [block] in calls to [Canvas.save]/[Canvas.translate]
* and [Canvas.restoreToCount].
*/
inline fun Canvas.withTranslation(
x: Float = 0.0f,
y: Float = 0.0f,
block: Canvas.() -> Unit
) {
val checkpoint = save()
translate(x, y)
try {
block()
} finally {
restoreToCount(checkpoint)
}
}

Taking a deeper look into how this extension function works, we can see that the functions wrap up the logic of saving and restoring the canvas. The last parameter is a function and that function (block()) is a function literal with receiver. This sounds complicated but this just means that the Canvas instance then becomes the this scope for that function definition. 

This allows us in the block() function, to call the Canvas methods without having to specify the canvas object directly. For example, we don’t have to call canvas.drawCircle() anymore, we can now just call drawCircle() and the correct Canvas object will be used for that method call. 

The block param is the last parameter of the function (and it is a function itself) so we are able to extract the block function outside of the parentheses. For example, both of the following usages are acceptable:

canvas.withTranslate(200f, 300f, {
drawCircle(...)
})

Outside of parenthesis:

canvas.withTranslate(200f, 300f) {
drawCircle(...)
}

It is worth noting that in Android Studio, the first example here will produce a lint warning to tell you to rather use the second option. 

What a nifty mechanism for cleaning up our Canvas API interactions!

Finally… ✨

We can see how the AndroidX Canvas Extension functions can help improve the readability of our canvas transformation code. There are a few other extension functions for Canvas, some of the others include:

  • Canvas#withScale() 
  • Canvas#withSkew() 
  • Canvas#withMatrix()

Have you found any other useful extension functions in the KTX library? Let me know on Twitter @riggaroo 

Thanks to Nick Rout and Josh Leibstein for reviewing this post. 

Building Responsive / Resizable Android UIs for ChromeOS 📐📏

Building Responsive / Resizable Android UIs for ChromeOS 📐📏

Learn how using ViewModels can help create great user experiences on ChromeOS

This post originally appeared here.

Supporting ChromeOS devices sounds like a large undertaking with many unknowns. If you didn’t know already, ChromeOS allows users to install Android Apps on their devices. This is great news for ChromeOS users since it unlocks a huge amount of apps that previously weren’t available to them.

Why should you build support for ChromeOS?

ChromeOS support seems like a big task that you may not think is important to implement. But if you do a bit of research into the Chromebook usage, you will see that there is a large portion of the US market that uses Chromebooks. ChromeOS made up 59.6% of mobile computing sales in the US in Q4 of 2017 (according to this article) and whilst in the rest of the world ChromeOS isn’t as popular, it is steadily gaining in popularity. Considering that you can pick up a Chromebook for about $150, you can understand why it might be appealing to purchase.

How to build support in your Android app for ChromeOS?

Spoiler Alert: You don’t need to do anything fancy to enable your Android apps to run on ChromeOS. If your app supports tablets, your app will run on ChromeOS. There are extra options you can consider for a ChromeOS device, such as support for a Stylus and possibly support for if a user doesn’t have a touch screen (If you want them to be able to use your app without one).

Supporting the resizing of layouts can be a bit tricky. If you know what tools to use from the start, building support for this kind of interaction in your apps is something you can do from the beginning of building any new layout or app.

Since releasing the Over App on Android, we’ve been working to optimise our app for ChromeOS devices. But it turns out that we didn’t need to do thatmuch more in order to support it because we were already following best practices (as mostly described in this post). There is obviously room for improvement for us (keyboard shortcut support and UI optimisations). In this article, we will cover how to ensure that your UI remains consistent during app window resizes.

Use ViewModels for storing UI State

If you’ve been out of action in Android for a while, you may have missed all the great libraries that have been released recently that help to solve some complex Android specific issues. ViewModels are a new class available from Android Jetpack.

This is the definition of a ViewModel from the Android Developer docs:

ViewModels help store and manage UI-related data in a lifecycle aware way. The ViewModelclass allows data to survive configuration changes such as screen rotations.

With this definition in mind, this is how ChromeOS handles the lifecycle when resizing an app: It notifies your app of a screen size change, which typically would trigger a new creation of your Activity class. Now if you aren’t using something like a ViewModel, when the new activity is created, you would losethe data that you have backing that view. Since ViewModels have a different lifecycle than an Activity, they outlive a recreation of it.

ViewModel Lifecycle from Android Developer Documentation

In our case, we have our layout state stored in the ViewModel and as such, when a user resizes the app window, the state outlives the Activity and the view automatically keeps the same information after it is being resized.

Our ViewModel looks something like this:

class ProjectEditorViewModel : ViewModel() {

    private val _state = MutableLiveData<EditorState>()
    val state: LiveData<EditorState>
        get() = _state

}

The usage of this ViewModel in our ProjectEditorFragment, looks like the code below:

class ProjectEditorFragment : Fragment {

    @Inject
    lateinit var viewModelFactory: ViewModelProvider.Factory

    private lateinit var viewModel: ProjectEditorViewModel

 
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.fragment_editor_initial, container, false)
        AndroidSupportInjection.inject(this)

        return view
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        viewModel = ViewModelProviders.of(requireActivity(), viewModelFactory)
            .get(ProjectEditorViewModel::class.java)
        setupViewModel()
    }
    
    private fun setupViewModel() {
        viewModel.state.observe(this, Observer { editorState ->
            editorState?.let { state ->
                // Set the state of all controls based on the saved state in the ViewModel 
            }
        })
    }
}

In the sample above, you can see that we have the ProjectEditorViewModelstate being observed for changes. When a new state comes in from the ViewModel, we will then perform all the required changes in order to update the view’s state.

Resizing the Editor Experience keeps a user’s selected tool state and their project state due to using ViewModels.

If we stored our state in a class that wasn’t extending ViewModel or AndroidViewModel, when the activity is resized, the UI information would be lost (i.e. A user’s project changes, the state of the currently selected tool etc.).

With us using ViewModels by default for all our UI state, resizing an activity didn’t present any weird state loss issues. 🎉

Support multiple screen sizes using best practices

Now that we’ve covered how you can go about storing state across window resizing, we might want to transition our layouts in a way that communicates the change in UI. Of course, this is not the only thing you need to do in order to support ChromeOS devices.

There are great guidelines that already exist on how to build for different screen/density size buckets. Follow those in order to support different layout sizes (i.e. Create different size buckets, layout params etc.).

Finally

If you start doing these few things you won’t have to retrospectively go back and change your app to support ChromeOS. The great part about using the suggestions above is that it doesn’t just apply to ChromeOS but also to tablets or phones when you use the split screen feature on any Android device.

There are a few more things you can do to support ChromeOS really well, including supporting a stylus and making sure your app has some delightful keyboard shortcuts. We are getting there!

If you have any questions, feel free to reach out to me on Twitter @riggaroo.

Thanks to Joshua Leibstein and Nick Rout for reviewing this post.

[HOW TO] Set up Kotlin Source Code & Tests in your Android Apps

[HOW TO] Set up Kotlin Source Code & Tests in your Android Apps

After reading a lot of different posts raving about Kotlin, I couldn’t help myself. I had some serious FOMO. In this blog post, I will be looking at getting Kotlin set up in existing Android Apps.

What is Kotlin?

Kotlin is a statically typed programming language that can be used to write Android Apps. It is made by JetBrains, the same guys who make IntelliJ, Resharper and other awesome tools.

What does Kotlin code look like?

Below is how you would declare a function in Kotlin:

fun sum(a: Int, b: Int): Int {
  return a + b
}

As you can see there are a few notable differences from Java:

  1. The lack of semicolons (Yay right?).
  2. The declaration of the return type is at the end of the function definition.
  3. The type of the parameters are defined after the parameter name.

For more basic syntax differences, you can read more here.

Why is it better than Java?

A quick summary of Kotlin’s Advantages over Java:

This video by Jake Wharton highlights the differences between Java and Kotlin quite well. There are more links at the end of this blog post.

So now that we know what Kotlin is and why we might want to use it for our Android Apps. Lets take a look at getting set up in our existing Android Project.

Setting up your existing Android Project to use Kotlin

  1. Install the Kotlin plugin for Android Studio :
    • Go to “Preferences”→ “Plugins”→ “Install JetBrains Plugin”→ Type “Kotlin” in the search box→ Select “Kotlin” and install it. You will probably need to restart Android Studio for the settings to take effect.Kotlin Plugin in Settings Menu - Android Studio
  2. Go to your project level build.gradle file and add the following line into the classpath section
    buildscript {
        repositories {
            jcenter()
        }
        dependencies {
            classpath "com.android.tools.build:gradle:2.0.0-alpha3"
            classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3'
            classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.0.0-beta-4584"
        }
    }
  3. In your app level build.gradle  add the following:
    buildscript {
        repositories {
            maven { url 'https://maven.fabric.io/public' }
        }
    
        dependencies {
            classpath 'io.fabric.tools:gradle:1.+'
        }
    }
    apply plugin: 'com.android.application'
    apply plugin: 'kotlin-android'
    
    android {
        ...
        sourceSets {
            main.java.srcDirs += 'src/main/kotlin'
        }
    }
    
    dependencies {
        ...
        compile 'org.jetbrains.kotlin:kotlin-stdlib:1.0.0-beta-4584'
      
    }
    
  4. Create a folder in your app/src/main/  folder called kotlin . You can then create a folder with your package name, so for my example it would be org.bookdash.android.(You can also add kotlin files into the same directory as the Java files, I just prefer to separate them out by language.)
    Folder Structure when using kotlin programming language in android studio
  5. To add a new Kotlin class, right click on the package name and click “New -> Kotlin File or class”. Give it a name, select the type and you can start writing Kotlin code!How to Add new Kotlin class file in Android Studio

Convert existing Java files to Kotlin

In Android Studio if you want to convert a Java class to Kotlin, do the following:

  1. Open the file you wish to convert
  2. Run the following command. (Navigate to Action):
    • MacOs: CMD + Shift + A
    • Linux & Windows: CNTRL + Shift + A
  3. Then type “kotlin”, you should see the option to convert existing Java file into Kotlin.  Convert existing Java code to Kotlin
  4. This will take the Java file that you are in and convert it into a Kotlin class. I would make sure that the code that is generated is okay. I am always a bit worried about generated code not working. 😁
  5. I converted the AboutActivity  from my Book Dash App to use Kotlin, this is the result:
    class AboutActivity : BaseAppCompatActivity(), AboutContract.View {
    
        private var aboutPresenter: AboutPresenter? = null
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_about)
            aboutPresenter = AboutPresenter(this)
    
            val toolbar = findViewById(R.id.toolbar) as Toolbar
            setSupportActionBar(toolbar)
            val actionBar = supportActionBar
    
            if (actionBar != null) {
                actionBar.setDisplayHomeAsUpEnabled(true)
                actionBar.setTitle(R.string.about_heading)
            }
    
            val textViewWhyBookDash = findViewById(R.id.text_why_bookdash) as TextView
            textViewWhyBookDash.text = Html.fromHtml(getString(R.string.why_bookdash))
            Linkify.addLinks(textViewWhyBookDash, Linkify.ALL)
            ...
        }
    
        override fun showLearnMorePage(url: String) {
            val intent = Intent(Intent.ACTION_VIEW)
            intent.setData(Uri.parse(url))
            startActivity(intent)
        }
    }

    If you want to see an example of an app using Kotlin and Java, you can check out my github project, the Feature-Kotlin-AboutActivity branch.

Writing Tests in Kotlin

After getting some code written in Kotlin, I thought it would be great to see if I could set up some Android tests in Kotlin. Here is how to do it:

  1. In your androidTest folder create a kotlin folder
  2. Create your package name that matches the package you are testing.Getting Android Tests set up in Kotlin
  3. In your app build.gradle file, add the following:
    android {
        ...
        sourceSets {
            main.java.srcDirs += 'src/main/kotlin'
            androidTest.java.srcDirs += 'src/androidTest/kotlin'
        }
    
    }

    Adding that line tells Gradle that it should also look in the kotlin folder for source code and it should include it when building.

  4. Then you can start adding code to that folder. Below is an example of my AboutActivityTest  which does some basic espresso testing in Kotlin.
    @RunWith(AndroidJUnit4::class)
    @SmallTest
    class AboutActivityTest {
    
        @Rule
        fun getRule() = ActivityTestRule(AboutActivity::class.java)
    
    
        @Before
        fun setUp() {
            Intents.init()
        }
    
        @After
        fun tearDown() {
            Intents.release()
        }
    
        @Test
        @Throws(Throwable::class)
        fun loadAboutBookDash_SeeInformation() {
            val about = Html.fromHtml(InstrumentationRegistry.getTargetContext().getString(R.string.why_bookdash))
            val headingAbout = InstrumentationRegistry.getTargetContext().getString(R.string.heading_about)
    
            onView(withText(headingAbout)).check(matches(isDisplayed()))
    
            onView(withText(about.toString())).perform(scrollTo()).check(matches(isDisplayed()))
    
        }
    
        @Test
        @Throws(Throwable::class)
        fun clickLearnMore_OpenBrowser() {
    
            onView(withText(R.string.learn_more)).perform(scrollTo(), click())
    
            intended(allOf(hasAction(Intent.ACTION_VIEW),
                    hasData(Uri.parse("http://bookdash.org"))))
        }
    
    }
    

    Why I like Kotlin

  • The code looks neater and concise (no more semi-colons)
  • It is not just for Android apps.  It runs on the JVM you can use it pretty much anywhere.
  • You can write in both Java and Kotlin in the same project, they work together.
  • Of course the Null Safety Lambdas , Extension functions are great too 😁

What next?

I suggest reading through the docs about the advantages of Kotlin and try out some Kotlin code on the website or in a sample app. Then go forth and #MakeKotlinApps!

I would love to know what your are experiences with it so far? Do you have any other tips or tricks to getting started with Kotlin?

Links:

Book Dash Android App Github

Why Kotlin is my next Programming Language

Kotlin – The swift of Android

Using Project Kotlin for Android

RedChain –  Github Project for Android App – Daily goal tracker written in Kotlin