using Kotlin for unit tests > Then, improves our Coding Conventions • Adding some rules to the official Coding Conventions • e.g. Prefer “.also { }” than “.apply { }” • e.g. Don’t omit types of properties. > June 2017 - Start using Kotlin in production • New code should be written in Kotlin • When adding new features to Java code, convert the code to Kotlin first
in LINE Android app Java code 6200 files (53%) 1048k lines (64%) Kotlin code 5450 files (47%) 593k lines (36%) (As of October 2019. Not including test code.)
in procedural-way rather than functional-way (e.g. RxJava) • No callback-hell > Similar to async/await in C#, JavaScript > Structured concurrency & Managed cancellation > Developed as experimental for a long while > Oct 2018 - Kotlin Coroutines 1.0.0 → We couldn’t adopt it when we started using Kotlin (April 2017)
lot of async code, and the code was written in many kinds of libraries… • android.os.AsyncTask • java.util.concurrent.Executor + callbacks • RxJava 1.x • RxJava 2.x • Our own async library • etc…
these async libraries. > But until recently, we couldn’t adopt Kotlin Coroutines. → First, we adopted RxJava2 entirely. → Then, transit it to Kotlin Coroutines later. Kotlin Coroutines has a utility library that allows Coroutines and RxJava2 to be used each other.
Kotlin Coroutines, functions that perform asynchronous tasks using RxJava2 should return Single<T>. > We call such functions as “async functions”. // async function fun fooAsync(param: Param): Single<Result> = …
= fetchJsonAsync(url).await() val fooData = getFooDataFor(json).await() showFooData(fooData) } > By using Coroutines, you can write multiple calls of async functions procedurally.
to Coroutines by rewriting async functions with suspending functions. // suspending function suspend fun foo(param: Param): Result = … > Suspending functions can be called without “.await()”.
we usually cancel subscriptions of Rx when Activities / Fragments are stopped. > So, we implemented a utility class to cancel Coroutines on Activity/ Fragment’s onStop(). AutoResetLifecycleScope https://github.com/line/lich/tree/master/lifecycle
introduce Kotlin Coroutines through RxJava2. > Implemented some utility classes for cancellation of Coroutines. > The utility classes and sample code using the MVVM pattern are published on GitHub: https://github.com/line/lich
• Extensibility - Easy to understand the scope of impact on changes. > Speed up the build time • LINE Android app has more than 1.6M lines! > Reduce the initial APK size on installation • By using Dynamic Feature Modules + on-demand delivery
a module, extract its Facade class. > A feature only exposes its Facade (and a few parameter classes). • The feature must be accessed through the Facade only. class FooFacade { fun launchFooActivity(messageId: String) { … } … }
launchFooActivity(messageId: String) } class FooFacadeImpl : FooFacade { override fun launchFooActivity(messageId: String) = … } > Other features only need to know the Facade interface.
instance of the Facade is needed to call the feature. > How about using Dependency Injection (DI)? • Existing DI libraries such as Dagger2 are very complex to set up for multi-module projects. > So, we developed a library that easily solves the dependency problem in multi-module projects. • https://github.com/line/lich/tree/master/component val fooFacade: FooFacade = … ←??? fooFacade.launchFooActivity(messageId)
// `by component()` provides the instance of FacadeImpl. private val fooFacade by component(FooFacade) fun startFooFeature(messageId: String) { fooFacade.launchFooActivity(messageId) } }
of a feature. > Let other modules call the feature only through the Facade. > Split the implementation of the feature as a module. > Use “Lich Component” library to get the instance of a Facade. • https://github.com/line/lich/tree/master/component