Recently kotlin flow is gaining a lot of attention. I have never done any reactive programming before so i thought now is a good time to learn it. Even though I have access to books and some articles I could not understand how to integrate it say on an existing app that does not have any rxjava. I tried looking for some sample but the only thing they would give me is very basic. Im really confuse about this reactive programming thing. For example, I have a list that I needed to get on database. Why would I use flow to get that data? If I visualize it as streams, that would give me one data each. While if I get that list I could get the whole list without waiting for each streams to come if I had use flow. I read a lot of articles about this kotlin flow, even rx java. But still, I wanted to understand why streams and how is it any different from other way like the example I just gave?
For example, I have a list that I needed to get on database. Why would I use flow to get that data?
Well, that depends entirely on what you are using to access that database and how it uses Flow.
Let's suppose that you are using Room from the Android Jetpack. In that case, you can use Kotlin coroutines in two ways, via suspend functions and via Flow:
#Query("SELECT * FROM stuff")
suspend fun getStuff(): List<Stuff>
#Query("SELECT * FROM stuff")
fun getStuffNowPlusChanges(): Flow<List<Stuff>>
In both cases, Room will do the database I/O on a background thread, and you can use coroutines to get the results on your desired thread (e.g., Android's main application thread). And initially, the results will be the same: you get a List<Stuff> representing the current contents of the stuff table.
The difference is what happens when the data changes.
In the case of the suspend function, you get just the one List<Stuff> from the point when you call the function. If you change the data in the stuff table, you would need to arrange to call that function again.
However, in the case of the Flow-returning function, if you change the data in the stuff table while you still have an observer of that Flow, the observer will get a fresh List<Stuff> automatically. You do not need to manually call some function again — Room handles that for you.
You will have to decide whether that particular feature is useful to you or not. And if you are using something else for database access, you will need to see if it supports Flow and how Flow is used.
Related
I have come across articles that recommend switching to StateFlow.
Like the one here.
Also in the new Android studio, StateFlow support is automatically included in the functionality of data binding, including the coroutines dependencies.
Live data is already in use in most of the apps.
Should we migrate from LiveData to StateFlow? What are the benefits?
There is not much difference between State Flow and Live Data. The Main difference come in that State Flow requires an Initial value hence no need to check for nullability. The Second Difference come in unregistering the consumer; Live Data does this automatically when the view goes to STOPPED state while State Flow does not. To achieve similar behaviour as Live Data, you can collect the flow in a Lifecycle.repeatOnLifecycle block.
Benefits of State Flow
State flow is included in coroutines library and can be used in Multiplatform Projects
Using one API in your project(Flow), not two (LiveData and Flow).
It's Kotlin, Why Not
It depends on what you want,
If you want a manual, full and versatile control over the app , go for state flow
If you want a partially automatic or relatively easy-to-use method for your app , I will say - stick with live data
In case If you want to know my personal opinion, it's state flow, as i prefer control over easy-to-use. I don't mind writing a few extra lines for it as it can be useful for me sometimes.
Think of it like using a soda opener for soda and using a nail cutter
I can do it with both but the soda opener Is easy to use in this case but , don't have much versatility like nail cutter.
And at the end of the day , I use state flow everytime because, I am lazy to learn live data for some projects as state flow can do what live data can even though live data will be much easier.
And you should decide what you want to choose and if you're not as lazy as me , I recommend go with both and use the one which is suitable each time.
Cheers.
Flow is the best practice
Livedata is used to observe data without having any hazel to handle lifecycle problems. Whereas Kotlin flow is used for continuous data integration and it also simplified the asynchronous programming.
Take Room Library as an example. First, it used livedata to transmit data from the database to UI. It solved most of the existing problems. But when there are any future changes in the database livedata is helpless in this situation.
After a while, the room used Kotlin flow to solve this problem. With Flow as return-type, room created a new possibility of seamless data integration across the app between database and UI without writing any extra code
read this article on medium website
In Android, LiveData and State are two classes that can be used to hold and observe data in your app. Both classes are part of the Android Architecture Components library, which is a set of libraries for building robust, testable, and maintainable apps.
LiveData is a data holder that is lifecycle-aware, meaning it only delivers updates to observers that are in an active state. It is useful for holding data that needs to be observed and updated in the UI, such as data from a network request or a database query.
State is a data holder that represents an immutable state value that can be observed. It is useful for holding data that does not change often, or data that should not be modified directly.
Which of these classes is "best" to use depends on your specific needs and requirements. Here are a few factors to consider when deciding between LiveData and State:
Mutability: LiveData is mutable, meaning its value can be changed, while State is immutable, meaning its value cannot be changed directly.
Lifecycle awareness: LiveData is lifecycle-aware, while State is not.
Transformation: LiveData supports transformation through the use of the Transformations class, while State does not.
In general, if you need to hold and observe data that needs to be updated in the UI and you want the data to be lifecycle-aware, LiveData is a good choice. If you need to hold and observe data that is immutable or does not change often, State is a good choice.
It is also worth considering whether you need to transform or map the data being held and observed. If you do, LiveData is a better choice because it supports transformation through the Transformations class.
Context: I have an app that sends the same request several times depending on user interaction.
I need to reduce as much as possible the IO operations, so my idea is to somehow enqueue the requests until the first one resolves. Then use the fetched data on the enqueued requests.
I think that one way to accomplish this would be using Java concurrency APIs (BlockingQueue, to name one).
I'm already using Coroutines and suspend functions and would be great use them for this, but sadly my current knowledge on those subjects is not enough yet.
Sample:
suspend fun getDataAndCalculate(): Int {
val data = remote.getDataFromServer()
return calculate(data)
}
Function getDataAndCalculate() can be invoked multiple times and from multiple threads, it would be great to somehow enqueue or suspend all these invocations while remote.getDataFromServer() is in execution. When remote.getDataFromServer() returns use data in all pending getDataAndCalculate() invocations.
¿Any idea or recommendation, please? ¿Is this recommended? ¿Do you know any design pattern to tackle this kind of problem?
Thanks!
(Not quite sure about the title, hope it describes what I want to accomplish, otherwise, I can improve it.)
One possible & simple solution I can think of:
Create an in-memory cache, simple save the returned value at your repository level. You can add a timestamp too, and verify at your suspend function level if you consider the response outdated.
Add a state which represents if a request is already running (a simple flag, like var isRunning: Boolean, and if it's already running just suspend until you have a cached value.
It might not be the best approach though, other simple solutions:
If you're familiar with Channels or Flows, you could write some debouncing logic probably
At your ViewModel level, check if the previous request finished or not. The same isRunning functionality, with the constraint that requests need to be launched from the same vm.
These can do the job, but it might not be the most elegant solutions
I am starting to work with new things that are developed by the developer community Android, one of them is Coroutines. I have used the LiveData
and I assumed while using them, they are also lifecycle safe, then why coroutines are introduced and how they are different from LiveData. I have seen the video on Coroutines at Youtube, from developer channel, but I don't understand that completely. How Suspend and Resume works better than LiveData.
Ok first of all coroutines don't really relate too much with LiveData although they might share here and there some concepts.
Coroutines are used to perform async operation: Retreive data from network, database etc.
Coroutines can be used as "LiveData" if you are talking in the context of Channels or Flows (which I don't recomend because you will lose the lifecycle in it). With coroutines you can switch to threads easily.
Suspend functions are just functions that hold and don't run directly. Any suspending function should be inside a coroutine.
The simplest use case I can give you is this:
runBlocking{
//you are inside of a coroutine
val data = getDataFromBackground()
}
suspend fun getDataFromBackground(): SomeDataType = receiveSomeData()
The receiveSomeData method is also marked with suspend keyword.
But of course there is a lot more. The documentation is perfect way to start.
I also have a personal article about coroutines, you may find them easy there.
There is only one point I can think of that you can replace data with coroutines, and that's using Channels. The view won't be observing for LiveData but will be consuming values comming from a channel, created and shared with DI or something.
EDIT:
If you really want to use LiveData + coroutines please check this awesome library by the Android team.
Coroutines is for asynchronous job. Live Data are used to update your View (Activity & Fragment)
A bit of history: I used to code on main frames with COBOL back in the 90s when top down programming was all that was needed. I then lived through 2-tier, 3-tier and n-tier programming, so I understand abstracting the UI layer from the data layer, but the use of a content provider seems very restrictive and frankly counter intuitive.
I like the concept of abstracting the UI code from the data layer code, but the way the ContentProvider (CP) works seems to break this model. For instance, let's look at an example of an insert/update. Using N-tier, the UI code would call the data abstraction layer with a specific ItemID which would then hand back a POCO for the UI to use. The UI only needed to know about the getters and setters for data binding to work. When it came time to update/insert, the UI code would simply hand the POCO back to the data layer which would then determine if the item needed to be updated or inserted. The UI code didn't need to be concerned with HOW the data got to the DB, only that it either succeeded or failed.
With a CP, the UI code needs to know which URI to use to query based on getting a list of items or a specific item (which I am ok with). But both URIs return a cursor that I have to pass to my POCO which then populates the values so they can be changed by my data binding because cursors can't be updated. Then the UI code must determine whether the POCO needs to be updated or inserted and make a call to the appropriate function again using a specific URI. It then has to build a list of all the fields and all the values that need to be updated as well as providing a selection list to update the DB with.
It seems wrong for the UI layer to have to know about any of these items. Shouldn't all of that be encapsulated within the CP? It really seems to break the abstraction model entirely. What am I missing here with this new fangled technology?
BTW, I've already written an app using a CP so I understand HOW it works, I just don't understand the advantages of WHY it works the way it does. Other than keeping track of changes to data sourced by the CP and automagically updating them in the UI it seems like a lot of unnecessary overhead and programming and the implementation FEELS wrong.
While refractoring an app I decided to use room (and other architecture components). Everything went well until I reached database querying, which is async. It is fine by me, I can update views with LiveData callbacks.
But the problem arose with smaller queries following each other - with no thread restrictions it was easy, you could use variables straight away.
In legacy code there are plenty of setups, where quite many small data pieces are required one after another, from different tables. E.g., querying if item exists in one table, some calculations, querying another table, etc.
Disabling async requirement for queries is not an option, I prefer using Room as intended.
First thought was to nest callbacks, but it is too ugly.
Second thought was to query for all required data, start a method only after receiving all callbacks. It also does not sound nice and there are cases where one callback has data required for the other query.
Strangely I have not found any related forum posts or articles dealing with this problem.
Did anyone handle it already? Any ideas?
Most #Dao methods are synchronous, returning their results on whatever thread you call them on. The exceptions are #Query methods with reactive return types, such as Maybe<List<Goal>> or LiveData<List<Goal>>, where the methods return the reactive type and the results are delivered asynchronously to subscribers.
So, for cases where you have more complex business logic, you have three main courses of action (that I can think of right now):
Use RxJava and try to squish all that business logic into an observable chain. There are a lot of RxJava operators, and so some combination of map(), flatMap(), switchMap(), weAreLostWhereDidWePutTheMap(), etc. might suffice.
Do the work on a background thread, mediated by a LiveData subclass, so the consumer can subscribe to the LiveData.
Use classic threading options (e.g., IntentService) or more modern replacements (e.g., JobIntentService).