<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Anna Zharkova</title>
    <description>The latest articles on Forem by Anna Zharkova (@anioutkajarkova).</description>
    <link>https://forem.com/anioutkajarkova</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F556202%2F4c9afa60-9d7d-4ca1-b5f0-fbd61117be4e.jpg</url>
      <title>Forem: Anna Zharkova</title>
      <link>https://forem.com/anioutkajarkova</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/anioutkajarkova"/>
    <language>en</language>
    <item>
      <title>Kotlin Multiplatform. Practical multithreading (part 2)</title>
      <dc:creator>Anna Zharkova</dc:creator>
      <pubDate>Wed, 20 Jan 2021 13:28:19 +0000</pubDate>
      <link>https://forem.com/anioutkajarkova/kotlin-multiplatform-practical-multithreading-part-2-47po</link>
      <guid>https://forem.com/anioutkajarkova/kotlin-multiplatform-practical-multithreading-part-2-47po</guid>
      <description>&lt;p&gt;Hi everyone! My name is Anna Zharkova, I’m Lead Mobile developer in “Usetech” software company.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2Atbmc_gILwf_Q-_tDBFNViA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2Atbmc_gILwf_Q-_tDBFNViA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In previous &lt;a href="https://dev.to/anioutkajarkova/kotlin-multiplatform-practical-multithreading-part-1-4357"&gt;article&lt;/a&gt; I demontstrated one of the possible solutions to implement multitheading in Kotlin Multiplatform application. In this part I’m going to describe another solution, it will be KMM application with fully shared common code and common multithreading in shared business logic.   &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AXv2L7roxS1nyUFNa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AXv2L7roxS1nyUFNa.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In previous sample we used Ktor to make our common network client. This library makes all asynchronous work under its hood. In this case we have no need event to use DispatchQueue in our iOS native application. But in other cases we should use queues to request our business logic correctly and process the result responses. We also used MainScope to call suspended methods in our native Android app.&lt;/p&gt;

&lt;p&gt;So if we want to implement multithreading in our shared code with common logic, we should use coroutines for all parts of our project, so we need to setup correct scopes and contexts of our coroutines.&lt;/p&gt;

&lt;p&gt;Let’s begin with something simple. First of all, we will create our intemediate architectual component. I will use MVP pattern, so I need to make my presenters. This presenter will call all the methods of the specified service in its own CoroutineScope initialized with the CoroutineContext:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class PresenterCoroutineScope(context: CoroutineContext) : CoroutineScope {
    private var onViewDetachJob = Job()
    override val coroutineContext: CoroutineContext = context + onViewDetachJob

    fun viewDetached() {
        onViewDetachJob.cancel()
    }
}

//base class 
abstract class BasePresenter(private val coroutineContext: CoroutineContext) {
    protected var view: T? = null
    protected lateinit var scope: PresenterCoroutineScope

    fun attachView(view: T) {
        scope = PresenterCoroutineScope(coroutineContext)
        this.view = view
        onViewAttached(view)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, as previously mentioned, the presenter requests service methods in specified scope and then deliver the results to our UI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class MoviesPresenter:BasePresenter(defaultDispatcher){
    var view: IMoviesListView? = null

    fun loadData() {
        //call in scope
        scope.launch {
            service.getMoviesList{
                val result = it
                if (result.errorResponse == null) {
                    data = arrayListOf()
                    data.addAll(result.content?.articles ?: arrayListOf())
                    withContext(uiDispatcher){
                    view?.setupItems(data)
                   }
                }
            }
        }

//IMoviesListView - protocol to implement with UIViewController/Activity. 
interface IMoviesListView  {
  fun setupItems(items: List&amp;lt;MovieItem&amp;gt;)
}
class MoviesVC: UIViewController, IMoviesListView {
private lazy var presenter: IMoviesPresenter? = {
       let presenter = MoviesPresenter()
        presenter.attachView(view: self)
        return presenter
    }()

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        presenter?.attachView(view: self)
        self.loadMovies()
    }

    func loadMovies() {
        self.presenter?.loadMovies()
    }

   func setupItems(items: List&amp;lt;MovieItem&amp;gt;){}
//....

class MainActivity : AppCompatActivity(), IMoviesListView {
    val presenter: IMoviesPresenter = MoviesPresenter()

    override fun onResume() {
        super.onResume()
        presenter.attachView(this)
        presenter.loadMovies()
    }

   fun  setupItems(items: List&amp;lt;MovieItem&amp;gt;){}
//...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need to specify CoroutineDispatcher to initialize our CoroutineScope with CoroutineContext.&lt;/p&gt;

&lt;p&gt;We need to use a platform-specific code, that’s why we’re going to customize it with expect/actual mechanism.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expect val defaultDispatcher: CoroutineContext

expect val uiDispatcher: CoroutineContext
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;uiDispatcher should be used with UI-thread logic and other logic will be requested with defaultDispatcher.&lt;/p&gt;

&lt;p&gt;It could be easily done in our androidMain, because it uses Kotlin JVM, so there are default dispatchers for both cases. Dispatchers.Default is a default dispatcher for Coroutines mechanism:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;actual val uiDispatcher: CoroutineContext
    get() = Dispatchers.Main

actual val defaultDispatcher: CoroutineContext
    get() = Dispatchers.Default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CoroutineDispatcher uses specified fabric MainDispatcherLoader under the hood to create MainCoroutineDispatcher for requesting platform:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;internal object MainDispatcherLoader {

    private val FAST_SERVICE_LOADER_ENABLED = systemProp(FAST_SERVICE_LOADER_PROPERTY_NAME, true)

    @JvmField
    val dispatcher: MainCoroutineDispatcher = loadMainDispatcher()

    private fun loadMainDispatcher(): MainCoroutineDispatcher {
        return try {
            val factories = if (FAST_SERVICE_LOADER_ENABLED) {
                FastServiceLoader.loadMainDispatcherFactory()
            } else {
                // We are explicitly using the
                // `ServiceLoader.load(MyClass::class.java, MyClass::class.java.classLoader).iterator()`
                // form of the ServiceLoader call to enable R8 optimization when compiled on Android.
                ServiceLoader.load(
                        MainDispatcherFactory::class.java,
                        MainDispatcherFactory::class.java.classLoader
                ).iterator().asSequence().toList()
            }
            @Suppress("ConstantConditionIf")
            factories.maxBy { it.loadPriority }?.tryCreateDispatcher(factories)
                ?: createMissingDispatcher()
        } catch (e: Throwable) {
            // Service loader can throw an exception as well
            createMissingDispatcher(e)
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same mechanism used for DefaultDispatcher:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;internal object DefaultScheduler : ExperimentalCoroutineDispatcher() {
    val IO: CoroutineDispatcher = LimitingDispatcher(
        this,
        systemProp(IO_PARALLELISM_PROPERTY_NAME, 64.coerceAtLeast(AVAILABLE_PROCESSORS)),
        "Dispatchers.IO",
        TASK_PROBABLY_BLOCKING
    )

    override fun close() {
        throw UnsupportedOperationException("$DEFAULT_DISPATCHER_NAME cannot be closed")
    }

    override fun toString(): String = DEFAULT_DISPATCHER_NAME

    @InternalCoroutinesApi
    @Suppress("UNUSED")
    public fun toDebugString(): String = super.toString()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But not for all native platforms we can use existed default coroutine dispatchers. For example, such platforms as iOS work with KMM via Kotlin/Native, not Kotlin/JVM.&lt;/p&gt;

&lt;p&gt;So if we try to use the same implementation, as we used for Android, we will receive an error:   &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2Az151yPt_8_rQ4wh7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2Az151yPt_8_rQ4wh7.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s take a look, what has happened.&lt;/p&gt;

&lt;p&gt;GitHub Kotlin Coroutines  &lt;a href="https://github.com/Kotlin/kotlinx.coroutines/issues/470" rel="noopener noreferrer"&gt;Issue 470&lt;/a&gt;   contains information, that these special dispatchers for iOS haven’t been created in Kotlin/Native yet:   &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AXmhD-SVkLgICSJsJ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AXmhD-SVkLgICSJsJ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Issue 470 depends on  &lt;a href="https://github.com/Kotlin/kotlinx.coroutines/issues/462" rel="noopener noreferrer"&gt;Issue 462&lt;/a&gt;  , so it is also not resolved:   &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2ArS3g5aXwyr1P1ez4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2ArS3g5aXwyr1P1ez4.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recommended solution for our case is to create our own dispatchers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;actual val defaultDispatcher: CoroutineContext
get() = IODispatcher

actual val uiDispatcher: CoroutineContext
get() = MainDispatcher

private object MainDispatcher: CoroutineDispatcher(){
    override fun dispatch(context: CoroutineContext, block: Runnable) {
        dispatch_async(dispatch_get_main_queue()) {
            try {
                block.run()
            }catch (err: Throwable) {
                throw err
            }
        }
    }
}

private object IODispatcher: CoroutineDispatcher(){
    override fun dispatch(context: CoroutineContext, block: Runnable) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT.toLong(),
0.toULong())) {
            try {
                block.run()
            }catch (err: Throwable) {
                throw err
            }
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have created MainDispatch with DispatchQueue.main and IODispatcher with DispatchQueue.global(). When we launch our code, we will get the same error.&lt;/p&gt;

&lt;p&gt;The problem is, we cannot use dispatch_get_global_queue to dispatch our coroutines, because it is not bound to any particular thread in Kotlin/Native:   &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AEPoIt46vcXRwDT_U.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AEPoIt46vcXRwDT_U.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Secondly, Kotlin/Native doesn’t allow to move any mutable objects between threads. Included the coroutines.&lt;/p&gt;

&lt;p&gt;So we can try to use MainDispatcher for all our cases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;actual val ioDispatcher: CoroutineContext
get() = MainDispatcher

actual val uiDispatcher: CoroutineContext
get() = MainDispatcher


@ThreadLocal
private object MainDispatcher: CoroutineDispatcher(){
    override fun dispatch(context: CoroutineContext, block: Runnable) {
        dispatch_async(dispatch_get_main_queue()) {
            try {
                block.run().freeze()
            }catch (err: Throwable) {
                throw err
            }
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But it is not enough. We also should  &lt;a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native.concurrent/freeze.html" rel="noopener noreferrer"&gt;freeze&lt;/a&gt;   our objects before sharing the between threads. So we need to use freeze() command in this case:   &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AOcZIhmnh9SHlgiXE.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AOcZIhmnh9SHlgiXE.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But if we try to perform freeze() on already frozen object, FreezingException will be thrown. For example, all singletones are frozen by default.&lt;/p&gt;

&lt;p&gt;That’s why we should use @ThreadLocal annotation to share singletones and @SharedImmutable for global variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**
 * Marks a top level property with a backing field or an object as thread local.
 * The object remains mutable and it is possible to change its state,
 * but every thread will have a distinct copy of this object,
 * so changes in one thread are not reflected in another.
 *
 * The annotation has effect only in Kotlin/Native platform.
 *
 * PLEASE NOTE THAT THIS ANNOTATION MAY GO AWAY IN UPCOMING RELEASES.
 */
@Target(AnnotationTarget.PROPERTY, AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
public actual annotation class ThreadLocal

/**
 * Marks a top level property with a backing field as immutable.
 * It is possible to share the value of such property between multiple threads, but it becomes deeply frozen,
 * so no changes can be made to its state or the state of objects it refers to.
 *
 * The annotation has effect only in Kotlin/Native platform.
 *
 * PLEASE NOTE THAT THIS ANNOTATION MAY GO AWAY IN UPCOMING RELEASES.
 */
@Target(AnnotationTarget.PROPERTY)
@Retention(AnnotationRetention.BINARY)
public actual annotation class SharedImmutable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can simply use MainDispatcher for all our needs, when we use Ktor or another library that supports its own asynchronous processing. In common case for all long-running work we should use GlobalScope with the context of Dispatchers.Main/MainDispatcher:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//iOS
actual fun ktorScope(block: suspend () -&amp;gt; Unit) {
    GlobalScope.launch(MainDispatcher) { block() }
}

//Android
actual fun ktorScope(block: suspend () -&amp;gt; Unit) {
           GlobalScope.launch(Dispatchers.Main) { block() }
       }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we can easily perform the switching between contexts to our service logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;suspend fun loadMovies(callback:(MoviesList?)-&amp;gt;Unit) {
       ktorScope {
            val url =
                "http://api.themoviedb.org/3/discover/movie?api_key=KEY&amp;amp;page=1&amp;amp;sort_by=popularity.desc"
            val result = networkService.loadData&amp;lt;MoviesList&amp;gt;(url)
            //performing some long-running to demonstrate that MainDispatcher 
            //is not enough without GlobalScope in this case
            delay(1000)
           withContext(uiDispatcher) {
               callback(result)
           }
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We created the common scope for all code performing in same suspended function. So everything will work correctly. It is not the only way to implement coroutine based logic, you can organize it with any approach you prefer.&lt;/p&gt;

&lt;p&gt;You can also use wrapping blocks to share code with DispatchQueue.global():&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//You can specify any type of the response you need
actual fun callFreeze(callback: (Response)-&amp;gt;Unit) {
    val block = {
      //Just the sample of shared code
        callback(Response("from ios").freeze())
    }
    block.freeze()
    dispatch_async {
        queue = dispath_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND.toLong, 
            0.toULong())
        block = block     
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, you need to implement actual fun callFreeze(…) in androidMain, but you need just to put a callback into the completion block.&lt;/p&gt;

&lt;p&gt;Finally, we got a completed application that works same way in both platforms:   &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AsWW6gtdAexoxhjpC.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AsWW6gtdAexoxhjpC.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/anioutkazharkova/movies_kmp" rel="noopener noreferrer"&gt;Sample code&lt;/a&gt;&lt;br&gt;
One more sample:&lt;br&gt;
&lt;a href="https://github.com/anioutkazharkova/kmp_news_sample" rel="noopener noreferrer"&gt;github.com/anioutkazharkova/kmp_news_sample&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://tproger.ru/articles/creating-an-app-for-kotlin-multiplatform/" rel="noopener noreferrer"&gt;tproger.ru/articles/creating-an-app-for-kotlin-multiplatform&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/JetBrains/kotlin-native" rel="noopener noreferrer"&gt;github.com/JetBrains/kotlin-native&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/JetBrains/kotlin-native/blob/master/IMMUTABILITY.md" rel="noopener noreferrer"&gt;github.com/JetBrains/kotlin-native/blob/master/IMMUTABILITY.md&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/Kotlin/kotlinx.coroutines/issues/462" rel="noopener noreferrer"&gt;github.com/Kotlin/kotlinx.coroutines/issues/462&lt;/a&gt;&lt;br&gt;
&lt;a href="https://helw.net/2020/04/16/multithreading-in-kotlin-multiplatform-apps/" rel="noopener noreferrer"&gt;helw.net/2020/04/16/multithreading-in-kotlin-multiplatform-apps&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Originally published at  * &lt;a href="https://habr.com/ru/post/533952/" rel="noopener noreferrer"&gt;https://habr.com*&lt;/a&gt;     . *&lt;/p&gt;

&lt;p&gt;By  &lt;a href="https://medium.com/@anioutkazharkova" rel="noopener noreferrer"&gt;Anna Zharkova&lt;/a&gt;   on  &lt;a href="https://medium.com/p/1c20e6e36d4d" rel="noopener noreferrer"&gt;December 21, 2020&lt;/a&gt;    .&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/@anioutkazharkova/kotlin-multiplatform-practical-multithreading-part-2-1c20e6e36d4d" rel="noopener noreferrer"&gt;Canonical link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Exported from  &lt;a href="https://medium.com" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;   on January 20, 2021.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>mobile</category>
      <category>ios</category>
      <category>android</category>
    </item>
    <item>
      <title>Kotlin Multiplatform. Practical multithreading (part 1)</title>
      <dc:creator>Anna Zharkova</dc:creator>
      <pubDate>Wed, 20 Jan 2021 13:26:16 +0000</pubDate>
      <link>https://forem.com/anioutkajarkova/kotlin-multiplatform-practical-multithreading-part-1-4357</link>
      <guid>https://forem.com/anioutkajarkova/kotlin-multiplatform-practical-multithreading-part-1-4357</guid>
      <description>&lt;p&gt;&lt;em&gt;Hi everyone! My name is Anna Zharkova, I’m Lead Mobile developer in “Usetech” software company.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;I develop both native (iOS and Android) and cross-platform for a long time (7 years). I made a lot of stuff using Xamarin platform (iOS, Android native, also Forms). And I’m interested in different technologies of the code sharing, so Kotlin Multiplatform SDK is also interesting for me. Today I would like to talk, how can we use it in practice.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There are a lot of different samples how to create a simple basic KMM app. But I would like to demonstrate something more advanced, that we face in our daily tasks. So it will be a multithreading Kotlin Multiplatform app for both iOS/Android platforms.   &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AaOgBnqEuas6HamWR.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AaOgBnqEuas6HamWR.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At first, little bit introduction to Kotlin Multiplatform SDK. If you already know the basics of KMM, you can either scroll to the sample or read  &lt;a href="https://medium.com/p/1c20e6e36d4d" rel="noopener noreferrer"&gt;part 2&lt;/a&gt;   about more advanced case.&lt;/p&gt;

&lt;p&gt;The basic idea of KMM is common to other cross-platform technologies. Performing optimization of the development, write your code once and use it on all your platforms.&lt;/p&gt;

&lt;p&gt;According to the conception of JetBrains company, Kotlin Multiplatform is not a framework. It is an SDK to create your own codebase modules and connect them to your native projects.   &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AhNSTQd6Pd6dy8a_6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AhNSTQd6Pd6dy8a_6.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;KMM SDK uses the specific for every native platform versions of Kotlin: Kotlin/JVM, Kotlin/JS or Kotlin/Native. Every version includes special Kotlin language’s extensions, tools and libraries specified for particular platform.&lt;br&gt;
The module created with Kotlin language will be compiled into JVM bitecode for Android and into LLVM bitecode to iOS.&lt;/p&gt;

&lt;p&gt;Shared module contains all common reused business logic. Platform-specific modules for iOS/Android use the logic from the connected Shared modules as it is or implement its own solution depending on platform and its needs.&lt;/p&gt;

&lt;p&gt;Common business logic could contain:  -  common networks services;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; common database storages and service;&lt;/li&gt;
&lt;li&gt; data models, entities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It could also contain common architectural solutions for both platforms and all its parts not containing UI code:  -  ViewModel;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Presenter;&lt;/li&gt;
&lt;li&gt; Interactors and etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Kotlin Multiplatform and its conception can be compared with Xamarin. Though there is no code for UI implementation. All UI should be implemented in native projects.&lt;/p&gt;

&lt;p&gt;Let’s take a look how to apply it on practice.&lt;/p&gt;

&lt;p&gt;If you haven’t worked with KMM before, you need to install and setup tools. You need to download and install  &lt;a href="https://developer.android.com/studio" rel="noopener noreferrer"&gt;Android Studio 4.1)&lt;/a&gt;   and  &lt;a href="https://plugins.jetbrains.com/plugin/14936-kotlin-multiplatform-mobile?_ga=2.222289432.1256240536.1608381251-893400752.1607774396" rel="noopener noreferrer"&gt;Kotlin Multiplatform Mobile&lt;/a&gt;  plugin. Now you need to create your project with KMM Application template. The project with its basic structure will be created automatically.   &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2A99sbImR_OLXIfDrK.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2A99sbImR_OLXIfDrK.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kotlin Multiplatform project contains several modules of codes:  -  shared business logic (Shared, commonMain и т.п);&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; platform-specific ios logic (iOSMain, iOSTest);&lt;/li&gt;
&lt;li&gt; platform-specific android logic (androidMain, androidTest).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All our shared reusable business logic is in commonMain/kotlin and it could be also separated to different packages. All the functions, classes, objects and variables that should be reimplemented in platforms-specific code at first should be declared with expect modifier:   &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2ArAlsVAQ4eovIz3dK.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2ArAlsVAQ4eovIz3dK.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All implementations should use actual modifier&lt;/p&gt;

&lt;p&gt;Here is an example of simple multithreading application that uses open api:   &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2ArdtuBuN6btI9F_SU.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2ArdtuBuN6btI9F_SU.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My sample uses  &lt;a href="https://www.themoviedb.org" rel="noopener noreferrer"&gt;www.themoviedb.org&lt;/a&gt;  . You can find the link to its repo at the end of the article.&lt;/p&gt;

&lt;p&gt;All shared business logic is placed in Common project:   &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AkCVpwCqlOro5Lb-5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AkCVpwCqlOro5Lb-5.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will have common network service. It is easy.&lt;/p&gt;

&lt;p&gt;iOS/Android apps will contain only UI components and its special adapters. iOS app will be written on Swift, Android app will uses Kotlin.&lt;/p&gt;

&lt;p&gt;All business will be places in commonMain, that’s why we need to uses common Kotlin Multiplatform solutions:&lt;/p&gt;

&lt;p&gt;Ktor — library for networking and serialization.&lt;/p&gt;

&lt;p&gt;Let’s add following dependendencies in build.gradle (:app):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val ktorVersion = "1.4.0"
val serializationVersion = "1.0.0-RC"
 sourceSets {
        val commonMain by getting {
            dependencies {
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
                implementation("io.ktor:ktor-client-core:$ktorVersion")
                implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serializationVersion")
                implementation("io.ktor:ktor-client-serialization:$ktorVersion")
            }
        }
        val androidMain by getting {
            dependencies {
                //...
                implementation("io.ktor:ktor-client-android:$ktorVersion")
            }
        }
        val iosMain by getting {
            dependencies {
                implementation("io.ktor:ktor-client-ios:$ktorVersion")
            }
        }
        ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need to support serialization:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;plugins { //... kotlin("plugin.serialization") version "1.4.10" }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At that moment we should decide, how to implement multithreading. It is a platform-specific logic: we use GCD (Grand Central Dispatch) in iOS projects and JVM Threads and Coroutines for our Android app.&lt;br&gt;
Kotlin Multiplatform provides common solution for multithreading. It uses Kotlin, so we can use Coroutines, special version of every platform:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val coroutinesVersion = "1.3.9-native-mt"
 sourceSets {
        val commonMain by getting {
            dependencies {
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
               //...
            }
        }
        val androidMain by getting {
            dependencies {
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion")
               //...
            }
        }
        val iosMain by getting {
            dependencies {
                //...
            }
        }
        ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let’s provide some basics of Coroutines, because not every iOS developer knows about this technology. Coroutine it is a simple block of code that can be suspended without blocking its thread. It has its own context of running (CoroutineContext), it has a manager of its lifecycle (Job). It has its own CoroutineScope and its thread is specified with special CoroutineDispatcher.&lt;br&gt;
It could be compared with performing of code block in specified DispatchQueue in iOS or in specified NSThread. Or just like an Operation in OperationQueue. Even GlobalScope looks resemble to DispatchQueue.global(), аs MainScope to DispatchQueue.main.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Android
fun loadMovies() {
  GlobalScope.async {
    service.makeRequest()
   withContext(uiDispatcher) {
//...
}
  }
}

//iOS
func loadMovies() {
  DispatchQueue.global().async {
    service.makeRequest()
  DispatchQueue.main.async{
//...
}
}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All coroutines use suspend key word. This modifier doesn’t make method asynchronous, because it depends on other details of realization. It indicates that such function could be suspended without blocking its own thread. It also shows that this function could be called only from coroutine context.&lt;/p&gt;

&lt;p&gt;Ktor also uses coroutines for its asynchronous work, that’s why we call HttpClient from suspended function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Network service
class NetworkService {
     val httpClient = HttpClient {
        install(JsonFeature) {
            val json = kotlinx.serialization.json.Json { ignoreUnknownKeys = true }
            serializer = KotlinxSerializer(json)
        }
    }

    suspend inline fun &amp;lt;reified T&amp;gt; loadData(url: String): T? {
       return httpClient.get(url)
    }
}

//Movies service
 suspend fun loadMovies():MoviesList? {
        val url = MY_URL
        return networkService.loadData&amp;lt;MoviesList&amp;gt;(url)
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we added Kotlin Coroutines to our project, we haven’t specified any special version for iOS. It is not a mistake. Since Kotlin 1.4 it has basic support for suspending functions in Swift and Objective-C. All suspending functions are available as functions with callbacks and completion handlers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func getMovies() {
    self.networkService?.loadMovies {(movies, error) in 
      //...
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because Ktor makes all its work asynchronously under its hood, we have no need to use DispatchQueue in our iOS app.&lt;/p&gt;

&lt;p&gt;But in our Android app we should use coroutines to be able to call suspended functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fun getMovies() {
    mainScope.launch {
    val movies = this.networkService?.loadMovies()
//...
    }
}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, such implementation of multithreading can be used if we don’t need to have common architectural solution in both our native apps. In this case we implement only Common business logic. It is a work solution.&lt;/p&gt;

&lt;p&gt;If we need to create a fully shared common code project, with common architectural implementations connected with our UI with specified protocols, we should use another solution to provide multithreading.&lt;/p&gt;

&lt;p&gt;See it in  &lt;a href="https://dev.to/anioutkajarkova/kotlin-multiplatform-practical-multithreading-part-2-47po"&gt;part 2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source code  &lt;a href="https://github.com/anioutkazharkova/movies_kmp" rel="noopener noreferrer"&gt;github.com/anioutkazharkova/movies_kmp&lt;/a&gt;&lt;br&gt;
More info about &lt;a href="https://github.com/Kotlin/kotlinx.coroutines" rel="noopener noreferrer"&gt;coroutines&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Originally published at  * &lt;a href="https://habr.com/ru/post/533864/" rel="noopener noreferrer"&gt;https://habr.com*&lt;/a&gt;     . *&lt;/p&gt;

&lt;p&gt;By  &lt;a href="https://medium.com/@anioutkazharkova" rel="noopener noreferrer"&gt;Anna Zharkova&lt;/a&gt;   on  &lt;a href="https://medium.com/p/db8af265d5cc" rel="noopener noreferrer"&gt;December 21, 2020&lt;/a&gt;    .&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/@anioutkazharkova/kotlin-multiplatform-practical-multithreading-part-1-db8af265d5cc" rel="noopener noreferrer"&gt;Canonical link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Exported from  &lt;a href="https://medium.com" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;   on January 20, 2021.&lt;/p&gt;




&lt;p&gt;Originally published at &lt;a href="https://habr.com" rel="noopener noreferrer"&gt;https://habr.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>ios</category>
      <category>mobile</category>
      <category>android</category>
    </item>
  </channel>
</rss>
