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.
Related
My code is like this.
GlobalScope.launch {
while (true) { // do something.. }
}
It's somewhat awkward. :(
Is this right way?
You should not use GlobalScope for creating infinite loops . Since one of your tag mentions android , assuming you are writing program for the same , it is highly recommended that you use LifycycleScope / ViewModelScope when you are in Fragment-Activity / ViewModel respectively .
It is easy to accidentally create resource or memory leaks when GlobalScope is used. But since these scopes(lifecycleScope / viewModelScope) are lifecycle-aware , they will get automatically cancelled when the particular class(fragment/viewModel) is killed . Either you use one of the prebuilt-scope or create your own scope handling the lifecycle with viewLifecycleScope instead of using the GlobalScope for creating an infinite loop .
You can make use of viewModelScope in the following way :
fun runForever() {
// start a new coroutine in the ViewModel
viewModelScope.launch {
// cancelled when the ViewModel is cleared
while(true) {
delay(1_000)
// do something every second
}
}
}
The company I just started working at uses a so called Navigator, which I for now interpreted as a stateless ViewModel. My Navigator receives some usecases, with each contains 1 suspend function. The result of any of those usecases could end up in a single LiveData. The Navigator has no coroutine scope, so I pass the responsibility of scoping suspending to the Fragment using fetchValue().
Most current code in project has LiveData in the data layer, which I tried not to. Because of that, their livedata is linked from view to dao.
My simplified classes:
class MyFeatureNavigator(
getUrl1: getUrl1UseCase,
getUrl1: getUrl1UseCase
) {
val url = MediatorLiveData<String>()
fun goToUrl1() {
url.fetchValue { getUrl1() }
}
fun goToUrl2() {
url.fetchValue { getUrl2() }
}
fun <T> MediatorLiveData<T>.fetchValue(provideValue: suspend () -> T) {
val liveData = liveData { emit(provideValue()) }
addSource(liveData) {
removeSource(liveData)
value = it
}
}
}
class MyFeatureFragment : Fragment {
val viewModel: MyFeatureViewModel by viewModel()
val navigator: MyFeatureNavigator by inject()
fun onViewCreated() {
button.setOnClickListener { navigator.goToUrl1() }
navigator.url.observe(viewLifecycleOwner, Observer { url ->
openUrl(url)
})
}
}
My two questions:
Is fetchValue() a good way to link a suspend function to LiveData? Could it leak? Any other concerns?
My main reason to only use coroutines (and flow) in the data layer, is 'because Google said so'. What's a better reason for this? And: what's the best trade off in being consistent with the project and current good coding practices?
Is fetchValue() a good way to link a suspend function to LiveData?
Could it leak? Any other concerns?
Generally it should work. You probably should remove the previous source of the MediatorLiveData before adding new one, otherwise if you get two calls to fetchValue in a row, the first url can be slower to fetch, so it will come later and win.
I don't see any other correctness concerns, but this code is pretty complicated, creates a couple of intermediate objects and generally difficult to read.
My main reason to only use coroutines (and flow) in the data layer,
is 'because Google said so'. What's a better reason for this?
Google has provided a lot of useful extensions to use coroutines in the UI layer, e.g. take a look at this page. So obviously they encourage people to use it.
Probably you mean the recommendation to use LiveData instead of the Flow in the UI layer. That's not a strict rule and it has one reason: LiveData is a value holder, it keeps its value and provides it immediately to new subscribers without doing any work. That's particularly useful in the UI/ViewModel layer - when a configuration change happens and activity/fragment is recreated, the newly created activity/fragment uses the same view model, subscribes to the same LiveData and receives the value at no cost.
At the same time Flow is 'cold' and if you expose a flow from your view model, each reconfiguration will trigger a new flow collection and the flow will be to execute from scratch.
So e.g. if you fetch data from db or network, LiveData will just provide the last value to new subscriber and Flow will execute the costly db/network operation again.
So as I said there is no strict rule, it depends on the particular use-case. Also I find it very useful to use Flow in view models - it provides a lot of operators and makes the code clean and concise. But than I convert it to a LiveData with help of extensions like asLiveData() and expose this LiveData to the UI. This way I get best from both words - LiveData catches value between reconfigurations and Flow makes the code of view models nice and clean.
Also you can use latest StateFlow and SharedFlow often they also can help to overcome the mentioned Flow issue in the UI layer.
Back to your code, I would implement it like this:
class MyFeatureNavigator(
getUrl1: getUrl1UseCase,
getUrl1: getUrl1UseCase
) {
private val currentUseCase = MutableStateFlow<UseCase?>(null)
val url = currentUseCase.filterNotNull().mapLatest { source -> source.getData()}.asLiveData()
fun goToUrl1() {
currentUseCase.value = getUrl1
}
fun goToUrl2() {
currentUseCase.value = getUrl2
}
}
This way there are no race conditions to care about and code is clean.
And: what's the best trade off in being consistent with the project
and current good coding practices?
That's an arguable question and it should be primarily team decision. In most projects I participated we adopted this rule: when fixing bugs, doing maintenance of existing code, one should follow the same style. When doing big refactoring/implementing new features one should use latest practices adopted by the team.
In the last Google I/O, Jose Alcerreca and Yigit Boyar told us that we should no longer use LiveData to fetch data. Now we should use suspend functions for one-shot fetches and use Kotlin's Flow to create a data stream. I agree that coroutines are great for one-shot fetching or other CRUD operations, such as inserting, etc. But in cases where I need a data stream, I don’t understand what advantages Flow gives me. It seems to me that LiveData is doing the same.
Example with Flow:
ViewModel
val items = repository.fetchItems().asLiveData()
Repository
fun fetchItems() = itemDao.getItems()
Dao
#Query("SELECT * FROM item")
fun getItems(): Flow<List<Item>>
Example with LiveData:
ViewModel
val items = repository.fetchItems()
Repository
fun fetchItems() = itemDao.getItems()
Dao
#Query("SELECT * FROM item")
fun getItems(): LiveData<List<Item>>
I would also like to see some examples of projects using coroutines and Flow to work with the Room or Retrofit. I found only a Google's ToDo sample where coroutines are used for one-shot fetching and then manually refetch data on changing.
Flow is sort of a reactive stream ( like rxjava ). There are a bunch of different operators like .map, buffer() ( anyway less no. Of operator compared to rxJava ). So, one of the main difference between LiveData and Flow is that u can subscribe the map computation / transformation in some other thread using
flowOn(Dispatcher....).
So, for eg :-
flowOf("A","B","C").map { compute(it) }.flowOn(Dispatchers.IO).collect {...} // U can change the execution thread of the computation ( by default its in the same dispatcher as collect )
With LiveData and map , the above can't be achieved directly !
So its recommended to keep flow in the repository level , and make the livedata a bridge between the UI and the repository !
The main difference is that
Generally a regular flow is not lifecycle aware but liveData is lifecyle aware. ( we can use stateFlow in conjunction with repeatOnLifecycle to make it lifecycle aware )
flow has got a bunch of different operators which livedata doesn't have !
But again , Its up to u how do u wanna construct your project !
As the name suggests, you can think of Flow like a continuous flow of multiple asynchronously computed values. The main difference between LiveData and Flow, from my point of view, is that a Flow continuously emits results while LiveData will update when all the data is fetched and return all the values at once. In your example you are fetching single values, which is not exactly what Flow was dsigned for [update: use StateFlow for that].
I don't have a Room example but let's say you are rendering something that takes time, but you wanna display results while rendering and buffering the next results.
private fun render(stuffToPlay: List<Any>): Flow<Sample> = flow {
val sample = Sample()
// computationally intensive operation on stuffToPlay
Thread.sleep(2000)
emit(sample)
}
Then in your 'Playback' function you can for example display the results where stuffToPlay is a List of objects to render, like:
playbackJob = GlobalScope.launch(Dispatchers.Default) {
render(stuffToPlay)
.buffer(1000) // tells the Flow how many values should be calculated in advance
.onCompletion {
// gets called when all stuff got played
}
.collect{sample ->
// collect the next value in the buffered queue
// e.g. display sample
}
}
An important characteristic of Flow is that it's builder code (here render function) only gets executed, when it gets collected, hence its a cold stream.
You can also refer to the docs at Asynchronous Flow
Considering that Flow is part of Kotlin and LiveData is part of the androidx.lifecycle library, I think that Flow is used as part of the uses cases in clean architecture (without dependencies to the framework).
LiveData, on the other hand, is lifecycle aware, so is a match with ViewModel
I have all my architecture using livedata at this moment, but Flow looks like an interesting topic to study and adopt.
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.
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.