Has anyone given any decent thought about implemen...
# arrow
k
Has anyone given any decent thought about implementing an Android app using MVI architecture, but using Arrow/FP? I have been using an app I wrote as a personal project in MVVM style to learn other things, and first I learned MVI by refactoring it that way, and now I’ve been thinking about how one might use Arrow thoroughly. (my thoughts in thread)
For instance, when using classes like
ViewModel
, in MVI you have a state class wrapped in LiveData and your View observes the LiveData and on changes it re-renders itself using the data wrapped in LiveData. Your view issues actions/intents to the ViewModel, which then updates the state (triggering the re-rendering of View via the observer). Essentially, right now my contracts are (note that
State
is not the
State
monad from Arrow)
Copy code
interface ViewModelContract {
  val state: LiveData<MyState>
  fun instruct(action: Action): IO<Unit>
}

interface View {
  val viewModel: ViewModelContract
  fun render(MyState)
}
Right now I have my ViewModel function that receives the intents returning an IO<Unit> so the view can run
unsafeRunAsync
on the result of the viewmodel’s action receiver. The observer is set up in the view’s onCreate or something. Depends on whether it’s an Activity or Fragment. Wherever the view has to issue an action to the viewmodel, I have the call appended with
.unsafeRunAsync()
. Maybe this is a question better suited for another forum. Just thought I’d ask here, as I think someone from the Arrow team has described an MVP (or MVC, I forget) Android application using
Reader
.
But one thing I’ve wondered about is when my viewmodel’s init block has to make an IO call to load data from the repository. I end up needing to put an
unsafeRun…
inside my init block because it’s
Copy code
class MyViewModel … {
  init {
    IO.effect { someVal = repoCall() }.unsafeRunAsync {}
  }
  // ...
}
Instead of pushing it to the “edge” in my Activity/Fragment.
s
Loading from DB belongs in the VM. You don't wanna cancel the request in case of rotation, so VM is where it has to live
k
Yes, my loading from DB is in the VM. Did I write otherwise? I need to edit if I did because I inject the repo into my VM and make all my DB calls inside IOs in the VM.
Or @stojan were you just saying that I’m doing it right by having that
unsafeRunAsync
inside my VM’s init block? (Because if it were done in the view like
myViewModel.init().unsafeRunAsync {}
then I would run the risk of cancelling the call with a rotation?
I think I’ll share a Gist so I can make everything clearer
This is kind of what I’m thinking https://gist.github.com/kylegoetz/aabdcc7dd00c2907a8b8b2bee9c4ab49 Bear in mind this started as “traditional” MVVM and then to MVI and then to FP with Arrow, so it’s probably picked up code cruft that isn’t ideal.
a
Hi @kyleg! We're on the works for an Android module, ideally targeting mid year (after other big features come to the lib). So far there are few complications when using just arrow on android: rotation and keeping the state. For now I'd personally recommend using VM as you did and simply using IO to perform network/db/etc calls until something more useful comes
personally, I like to use IO to load the data I need + post a state to a view interface in a MVI-like style, but for now I always had to combine it with RxJava and ViewModels in order to have streams (will come to arrow) and a way to maintain the state (might come, not sure)
regarding the use of unsafeRunXXX we should be pragmatic, so even if ideally you would only use it from the view, I believe is perfectly fine calling it from the VM as, at the end, VM is nothing but another android component, so you could use it to just maintain your data/program and rely on another component for the business logic + easily add tests
I hope you're enjoying the lib, and please do not hesitate to report any issues (bugs, usability, etc), comments or ask anything! 🙌
k
Thanks, @aballano. I’ve certainly asked a few Qs here for sure 🙂 I tried to make it up to everyone by making some PRs for little “for noobs” documentation issues at the Arrow repo. It’s nice to know that despite feeling like I’m asking too many questions here, you haven’t even noticed, so I must not be asking too many! Since VM persists across rotations, if one holds view state in the VM and the view only renders the state, then rotation shouldn’t really have any proper side effects that we have control over, I don’t think. That’s one reason I started doing MVI. No more overriding
onDestroy
stuff to save state on rotation. I can’t say I’m advanced enough to be using the State monad, but it seems like my approach largely recreates the concept by having an immutable state that can only be changed by the VM that owns it, and in practice is only changed by a single function (that admittedly calls a few other VM-owned, private, pure functions just for readability’s sake) I’m looking forward to seeing the Android module. I don’t suppose it’s being developed “in public” on the repo? If not, no big deal, just thought I’d ask. It would be interesting to see what’s being considered. I saw yesterday that Jetpack has some experimental Compose module that was announced at Google ’19. I haven’t fiddled with it, but that plus Arrow looks like one could write some really functional apps. As for the pragmatic approach re unsafeRun, I agree. But since I’m new to this stuff, it’s easy for me to confuse pragmatism with ignorance: am I doing it this way because it’s actually better, or because my ignorance makes me think it’s better. 🙂