As part of working on the development of a new API, I am learning to use Kotlin. Initially I want the Kotlin API to be used within a Java (Android) project, but in the long term I hope to adopt Kotlin entirely.
As part of improving the implementation of a long-running process, I want to use coroutines. Specifically, a channel producer from the kotlinx.coroutines package.
For example:
fun exampleProducer() = produce {
send("Hello")
delay(1000)
send("World")
}
What is the best way to consume this in Java? I am okay with adding temporary 'helper' functions to Kotlin and/or Java.
The easiest way to interop channels with Java is via Reactive Streams. Both Rx and Project Reactor are supported out-of-the-box. For example, add kotlinx-coroutines-rx2 to your dependicies and you'll be able to use rxFlowable builder:
fun exampleFlowable() = rxFlowable<String> {
send("Hello")
delay(1000)
send("World")
}
This function returns an instance of Flowable, which is specifically designed for ease-of-use from Java, for example, you can do in Java:
exampleFlowable().subscribe(t -> System.out.print(t));
Currently, assuming Java 8 is used and lambdas are available, I rely on a helper function defined in Kotlin which allows passing a callback to consume incoming results.
The helper method in Kotlin:
fun exampleProducerCallback( callback: (String) -> Unit ) = runBlocking {
exampleProducer().consumeEach { callback( it ) }
}
This is then consumed in Java as:
ApiKt.exampleProducerCallback( text -> {
System.out.print( text );
return Unit.INSTANCE; // Needed since there is no void in Kotlin.
} );
Explanation on why return Unit.INSTANCE is needed can be found in this answer.
Related
How do I fix the deprecation warning in this code? Alternatively, are there any other options for doing this?
runOnUiThread {
doAsync {
// room insert query
}
}
// anko Commons
implementation "org.jetbrains.anko:anko-commons:0.10.8"
TLDR: I would honestly HIGHLY recommend making full use of Kotlin.
Since I do not know your exact purpose of Anko, I will answer very generally.
Anko was great, but now it is time to move on... Although there are several alternatives out there, Kotlin itself is the "Best" alternative to Anko
You could make all the general helper methods from Anko using Kotlin's Extension functions. (read more)
Like this:
fun MutableList<Int>.swap(index1: Int, index2: Int) {
val tmp = this[index1] // 'this' corresponds to the list
this[index1] = this[index2]
this[index2] = tmp
}
val list = mutableListOf(1, 2, 3)
list.swap(0, 2) // 'this' inside 'swap()' will hold the value of 'list'
You could use the state-of-the-art async programming library called Coroutine which Waaaaay faster than RxJava. (read more)
fun main() = runBlocking { // this: CoroutineScope
launch { // launch a new coroutine and continue
delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
println("World!") // print after delay
}
println("Hello") // main coroutine continues while a previous one is delayed
}
And much more to fulfill your needs.
Let me know if you have any questions.
As they say on their deprecation page on github, there are more alternatives. As for commons they provide two libs, all the links are here, keep in mind that some of these libs can be deprecated since last update of that page was 2 years ago.
My shared module contains Repository class which has two functions that return a list of items wrapped in a custom class extending Flow called CFlow.
I took the code for CFlow from kotlinconf-app and here:
fun <T> Flow<T>.asCFlow(): CFlow<T> = CFlow(this)
class CFlow<T>(private val origin: Flow<T>) : Flow<T> by origin {
fun watch(block: (T) -> Unit): Closeable {
val job = Job()
onEach {
block(it)
}.launchIn(CoroutineScope(Dispatchers.Main + job))
return object : Closeable {
override fun close() {
job.cancel()
}
}
}
}
Repository example functions:
fun getData1(): CFlow<List<Profile>>
fun getData2(): CFlow<List<String>>
When I try to call this functions in iOS swift code the return type of the functions get converted to CFlow<NSArray> and inside of watch function the type of array is Any.
This is weird because in both kotlinconf-app and here the return types of functions are preserved and there is no casting involved in their codebase.
Question: How can I make the type of CFlow to be known in Xcode iOS project?
Android Studio version: 4.1.1
Kotlin lang and plugin version: 1.4.21
Kotlin Multiplatform Mobile plugin version: 0.2.0
Xcode version: 12.2
right now the compiler can't understand nested generics. as a workaround for now, wrap your list inside a data class like this
data class ProfileResult(val data: List<Profile>)
fun getData1(): CFlow<ProfileResult>
it will give you a concrete type in ios
This is because there are no generics in Objective-C. Arrays are ordered collections of objects.
So using any generic collection type in Kotlin, will lose it's type when translated to NSArray
I believe you have three options here:
Wait for direct Kotlin - Swift interop (which is postponed currently)
Cast values in Swift
Don't use generics with collections. I'm personally not using the Flow wrapper currently and doing something like this:
fun observeItems(onChange: (List<Item>) -> Unit) {
items.onEach {
onChange(it)
}.launchIn(coroutineScope)
}
Exposing a dispose function to iOS
fun dispose() {
coroutineScope.cancel()
}
And consuming like this:
repo.observeItems { items in
...
}
But definitely this is more work and hopefully these interop issues will be solved along the way
I'm making an Android app using Kotlin for the first time using MVP pattern. My questions is, why do I need interfaces for View and Presenter as Kotlin provides higher order functions? Can't we just communicate using those higher order functions? Is the use of pattern without interfaces bad?
I have looked and read lots of article and tutorials but non answered my question. Is what I am doing in the code below a wrong practice? Can someone explain it to me?
In my Activity
override fun init() {
btn_login.setOnClickListener {
LoginPresenter.userLogin(et_emailAddress.text.toString(),et_password.text.toString()){
if (it){
//do something
}else{
//do something
}
}
}
}
My Presenter
object LoginPresenter {
fun userLogin(emailId: String, password: String, completion: (Boolean) -> Unit) {
//do something
completion(true)
}
}
Higher-order function costs
Kotlin official documentation on the cost of higher order functions
Using higher-order functions imposes certain runtime penalties: each
function is an object, and it captures a closure, i.e. those variables
that are accessed in the body of the function. Memory allocations
(both for function objects and classes) and virtual calls introduce
runtime overhead.
and if you're replacing all your interfaces with higher-order functions, you may end up with a bad performance.
2.
Interfaces can hold multiple functions, for which you'll need individual function params when using higher-order functions.
Consider the following case,
interface UserLoginInterface {
fun onLoginSuccess(loggedInUser: User)
fun onLoginFailure(error: ErrorResponse)
fun onRedirect(someOtherObjectWithDirectives: SomeDataClass)
}
To translate this to higher-order functions usage, You'll have to use three Function params
why do I need interfaces for View and Presenter as Kotlin provides higher order functions?
This is rather a common practice in software development. And while you may not use interfaces, there is a number of key points why interfaces are preferable. Off the top of my head:
with interface you can have multiple implementations of it without actually caring about the concrete type of the implementation. This is what you're missing with the higher order functions - you're restricted with the only type, LoginPresenter, when using the LoginPresenter.userLogin() method.
most of the design patterns is based on the separation of interfaces from their implementations. So programming into implementation rather than abstraction won't let you make use of those.
you won't be able to properly unit test classes that depend on other implementations as no mocking is possible in this case.
code maintenance and extension becomes much harder with concrete implementation.
In my Kotlin Multiplatform project, I'm trying to access Kotlin types defined in kotlin-stdlib from Swift.
TL;DR: StdLib types/methods seem not to result in header definitions, I'd like a solution that doesn't involve writing lots of boilerplate code
My scenario
I have an interface defined in Kotlin ...
interface MyKotlinInterface {
fun run() : Sequence<String>
}
... and implemented this interface in Swift ...
class MySwiftClass : MyKotlinInterface {
func run() -> KotlinSequence {
// return sequenceOf("foo")
}
}
... there I'm trying to create a Sequence but there are no methods from the kotlin.sequences package available (e.g. generateSequence).
Is it actually possible to access Kotlin framework types or methods beyond what I define in my code -- if yes, how? Furthermore, how can this be achieved without writing boilerplate code?
Further details
Having a look into the generated Objective-C header file, I see definitions for my class (obviously) and basic Kotlin types. What's missing is basically everything from the standard library functionality (I care for everything Sequence-related).
My build.gradle.kts looks like:
plugins {
kotlin("multiplatform") version "1.3.0"
}
kotlin {
targets { /* ... */ }
sourceSets {
getByName("commonMain") {
dependencies {
api("org.jetbrains.kotlin:kotlin-stdlib-common")
}
}
// ...
getByName("iosMain") {
dependencies {
api("org.jetbrains.kotlin:kotlin-stdlib")
}
}
}
}
Having the kotlin-stdlib defined as a dependency for the iOS target, I would expect those to become actually available from Swift.
Minimal working example
https://github.com/panzerfahrer/so-mwe-kotlin-mpp-swift
Current solution approach
The only solution I came up with, is writing the desired function for the iOS target:
fun <T : kotlin.Any> generateSequence(nextFunction: () -> T?): kotlin.sequences.Sequence<T> = kotlin.sequences.generateSequence(nextFunction)
This works ok-ish but is highly unsatisfying as it requires lots of boilerplate code. Additionally, extension functions cannot be made available this way and would require more boilerplate code or even rewriting parts of the standard library.
Desired solution
I like to avoid writing boilerplate code as much as possible. What I actually only care about, is to have (in my case) Sequence fully accessible from Swift. My feeling is, it would be sufficient to make the compiler generate selected or all header definitions for the standard library functionality.
Do you really need lazy computation (aka Sequence) in your Kotlin code?
If no, I would recommend using List<T> instead (and it maps to Swift directly).
For Sequence implementation, a workaround could be to export a factory function from your Kotlin library, e.g. you may declare a function like
fun <T : kotlin.Any> generateSequence(nextFunction: () -> T?)
= kotlin.sequences.generateSequence(nextFunction)
You may select any other factory function for Sequence, that matches your use-case.
In general, there are too many functions in the Kotlin standard library. Exporting them all to Swift will create too many useless symbols in the binary and increase the compilation time.
Since a while we're working with Kotlin and one of the things we're currently focussing on is using Coroutines to take care of operations we want to run async.
While the example usages are clear and that works, I'm having some issues integrating this in a clean manner within our architecture. When looking at a method's implementation for a domain-focussed class, the idea is that it's easy to read and there is as less "noise" as possible from async functionality. I know I can't have async, without actually using it. So writing something like this is what I'd like:
val data = someService.getData().await()
// work with data
But this is what I'd like to prevent:
launch(UI) {
val data
val job = async(CommonPool) {
data = someService.getData()
}
job.await()
// work with data
}
That, I'd like paired with practical Unit Tests for these domain-focussed classes, but I can't really get that to work. Let's look at an example:
// Some dependency doing heavy work
class ApiClient {
suspend fun doExpensiveOperation(): String {
delay(1000)
return "Expensive Result Set"
}
}
// Presenter Class
class Presenter(private val apiClient: ApiClient,
private val view: TextView) {
private lateinit var data: String
fun start() {
log("Starting Presenter")
runBlocking {
log("Fetching necessary data")
data = apiClient.doExpensiveOperation()
log("Received necessary data")
}
workWithData()
log("Started Presenter")
}
fun workWithData() {
log(data)
}
private fun log(text: String) {
view.append(text+"\n")
}
}
// In an Activity
val presenter = Presenter(ApiClient(), someTextView)
presenter.start()
That works (screenshot: https://imgur.com/a/xG9Xw). Now lets look at the test.
class PresenterTest {
// ... Declared fields
#Before
fun setUp() {
// Init mocks (apiClient, textView)
MockitoAnnotations.initMocks(this)
// Set mock responses
runBlocking {
given(apiClient.doExpensiveOperation()).willReturn("Some Value")
}
presenter = Presenter(apiClient, textView)
}
#Test
#Throws(Exception::class)
fun testThat_whenPresenterStarts_expectedResultShows() {
// When
presenter.start()
// Then
Mockito.verify(textView).text = "Some Value\n"
}
}
Now this test is less than ideal, but regardless, it never even gets to the point where it can verify things work as intended, because lateinit var data wasn't initialized. Now ultimately the aesthetics and readability of our domain classes is simply how far I want to go, which I have some practical working examples for that I'm happy with. But making my tests work seems to be challenging.
Now there's some different write-ups online about this kind of stuff, but nothing has really worked out for me. This (https://medium.com/#tonyowen/android-kotlin-coroutines-unit-test-16e984ba35b4) seems interesting, but I don't like the idea of a calling class launching a context for a presenter, because that in turn has a dependency that does some async work. Although as an abstract thought I like the idea of "Hey presenter, whatever you do, report back to me on a UI context", it rather feels as a fix to make things work, leading to a shared concern for async functionality across different objects.
Anyway, my question:
Moving away from the short examples, does anyone have any pointers on how to integrate coroutines within a bigger architecture, with working unit tests? I'm also very open to arguments that make me alter my way of viewing things, given that's it's convincing on a different level than "If you want things to work, you have to sacrifice.". This question goes beyond just making the example work, as that is just an isolated example, while I'm looking for a real solid integration within a big project.
Looking forward to your input. Thanks in advance.
I'd suggest an approach of having some kind of AsyncRunner interface and have two implementations of this AsyncRunner interface. One would be implementation for Android, using launch(UI), and the other would be some blocking implementation, using runBlocking.
Passing the right type of AsyncRunner into code run within app and code run in unit test should be done by dependency injection. In your code then, you'd not use coroutines directly, instead you'd use injected AsyncRunner to run asynchronous code.
Example implementations of this AsyncRunner might look like this:
interface AsyncRunner {
fun <T>runAsync(task: () -> T, completion: (T) -> Unit)
}
class AndroidCoroutineAsyncRunner: AsyncRunner {
override fun <T>runAsync(task: () -> T, completion: (T) -> Unit) {
launch(UI) {
completion(async(CommonPool) { task() }.await())
}
}
}
class BlockingCoroutineAsyncRunner: AsyncRunner {
override fun <T>runAsync(task: () -> T, completion: (T) -> Unit) {
runBlocking {
completion(async(CommonPool) { task() }.await())
}
}
}
where the task parameter represents the thread blocking code (for example fetching data from API) and completion parameter will get data from the task and do something with them.
You should abandon coroutines and use RxJava instead. There you will find the kind of conciseness and simplicity you seek. When I ask most developers why they use coroutines, their answer is always the same: "Well, coroutines are the new, new thing, and we should use the latest technology from Google". Except that coroutines are not new. They were first introduced in about 1952 (See "Coroutines" in Wikipedia) as a proposal for doing asynchronous software development. It is pretty clear that the Computer Science community rejected coroutines years ago as not being the best approach for asynchronous programming. Why JetBrains decided to introduce an old, rejected technology into Kotlin is something you will have to ask JetBrains. I have had to deal with coroutines in code that others have written for several years now, and I always find coroutines to be needlessly complex. There is no way that coroutines do anything more than decrease maintainability when maintenance developers have to deal with coroutine spaghetti written by a developer who has long since departed the project.
The next thing I hear from these same developers is that RxJava is old technology and coroutines are new technology. If they had done their research, they would never have made such an outrageously incorrect statement. IMHO, RxJava is the most important new development in asynchronous software development in the entire history of computer science.