This is the second part of android ktx tutorial. I hope you guy has seen my previous blog in which I briefly explain about fragment ktx, palette ktx, SQLite ktx and collection ktx extension functions. So in this blog, I’m gonna explain how we can use the extension function exists in ViewModel ktx and work-runtime ktx.

In this blog, I’m not gonna tell you how we can set up build. gradle file to use the android ktx. To see you have to check out my previous blog. So, let’s see what are the extension function that ViewModel ktx and work-runtime ktx have.

5. Lifecycle ViewModel-ktx:

There’s only two extension function that has been added to lifecycle view-model ktx. If we need to convert LiveData into Publisher then we have an extension function for this.

val myViewModel = MyViewModel()
val liveData : LiveData<T> =myViewModel.observeModel()
liveData.toPublisher(lifecycle : LifecycleOwner).subscribe(object : Subscriber<T>{
      override fun onComplete() {
      }

      override fun onNext(t: T?) {
      }

      override fun onError(t: Throwable?) {
      }

      override fun onSubscribe(s: Subscription?) {
      }
})

The toPublisher is the extension function which adapts the given LiveData streams into a reactive stream Publisher.

Let’s see another example to convert the LiveData into Publisher. Suppose we have a ViewModel which returns an array of String when we start listening to the stream. For this, we have to create a ViewModel which returns an array of String with LiveData.

ViewModel
class MyModel : ViewModel(), StringRepository {

    override fun getStrings(): LiveData<List<String>> {
        val stringsLiveData = MutableLiveData<List<String>>()
        stringsLiveData.postValue(Arrays.asList("Data", "return", "from", "view", "model"))
        return stringsLiveData
    }
}
StringRepository
interface StringRepository {

    fun getStrings(): LiveData<List<String>>
}

Now let’s see how we can listen to the array of String LiveData stream and convert into reactive stream Publisher.

MainActivity
val model = MyModel()
        model.getStrings().toPublisher(lifecycle = this).subscribe(object : Subscriber<List<String>> {
            override fun onComplete() {
            }

            override fun onSubscribe(s: Subscription?) {
            }

            override fun onNext(t: List<String>?) {
                  // Handle the data or show in the UI
            }

            override fun onError(t: Throwable?) {
            }

        })

Note: Only the UI observe the LiveData object. UI means your Activity or Fragment can only start listening to the data.

There’s another cool extension function in lifecycle ktx which converts the reactive stream Publisher to LiveData stream. Let’s say our StringRepository returns a Publisher instead of LiveData stream.

Now the StringRepository will look like this.

StringRepository
interface StringRepository {

    fun getStrings(): Publisher<List<String>>
}

You see our StringRepository class change it means ViewModel also have to update.

ViewModel
class MyModel : ViewModel(), MovieRepository {

    override fun getStrings(): Publisher<List<String>> {
        return Publisher {
            Arrays.asList("Data", "return", "from", "view", "model")
        }
    }
}

Now let’s see how we can create an observable LiveData stream from a reactive stream Publisher. This time MainActivity will look like this.

MainActivity
val model = MyModel()
        model.getStrings().toLiveData().observe(this, object : Observer<List<String>> {
            override fun onChanged(t: List<String>?) {
                // handle the data or show in the UI
            }
        })

The toLiveData is the extension function which gives us the feasibility to create an observable LiveData stream from reactive stream Publisher.

6. Work-Runtime-ktx:

Ktx also offers an extension function and a bunch of top-level function related to WorkManager. By the way, I wrote a pretty good article on how to work with WorkManager efficiently go and check it out. Let’s take a look at what there is currently an offer.

6.1 Work-Runtime-ktx Top-level Functions:

We can now create OneTimeWorkRequest.Builder directly with top-level function. The OneTimeWorkRequestBuilder is the top-level function. Let’s see an example of how we can create work request builder with top-level function.

val workRequest = OneTimeWorkRequestBuilder<MyWorker>()
                .build()

The PeriodicWorkRequest.Builder class also have a bunch of top-level to create work request builder. The PeriodicWorkRequestBuilder is the top-level function.

val workRequest = PeriodicWorkRequestBuilder<MyWorker>(10, TimeUnit.SECONDS)
                .build()

val workRequest = PeriodicWorkRequestBuilder<MyWork>(
                    repeatInterval : 10
                   , timeUnit : TimeUnit.SECONDS
                   , flexTimeInterval : 10
                   , timeUnit : TimeUnit.MINUTES)
                   .build()

The first periodic work executes the request every after 10 seconds when we enqueue this work request. The second periodic work request runs periodically once within the flex period of every interval period.

6.2 Work-Runtime-ktx Extension Functions:

The OneTimeWorkRequest.Builder also gives us an extension function to add an InputMerger when creating work request builder. InputMerger takes one or more Data inputs to a Worker and converts them to a single merged Data to be used as input.

Let’s see an example, how we can pass InputMerger when creating work request builder.

val workRequest = OneTimeWorkRequestBuilder<MyWork>()
                .setInputMerger(ArrayCreatingInputMerger::class.java)
                .setInputData(createInputData("Value1"))
                .build()


private fun createInputData(msg: String): Data {
    return Data.Builder().putString("Key", msg).build()
}

ArrayCreatingInputMerger creates an array in which all the values of this key are placed as an array. You can read about ArrayCreatingInputMerger here.

The input data that we passed when creating a work request builder will receive in Worker class. When setting input merger as ArrayCreatingInputMerger the result will always an array, even if there were no key matches.

Another cool extension functions in kotlin.collection.The Map which gives the ability to convert Map to the Data object.  You can create any Map data to work Data object with the help of extension function. Let’s see an example, how we can convert Map to the Data object.

private fun createInputData(msg: String): Data {
    val map = HashMap<String, String>()
    map["Key"] = msg
    return map.toWorkData()
}

You see in this function we’re using the toWorkData extension function to convert a map into the Data object.

That’s it guys, I’m going to end this blog here for more further reading about android ktx see the part 3. In the next part, we’re going to see the main core ktx extension function. Obviously, the core ktx have so many extension functions and top-level functions to explore.

I hope you guy’s have learned something from this post. If you’ve any queries please do comment below.

Thank you for being here and keep reading.

 

Author

I’m a mobile product devsigner (i.e. I consider myself as both a developer and a designer) and user experience/interface engineer. I’m an expert on the Android platform and have been recognized as it by the community.

Write A Comment