|
Volmarias posted:The change from MVC to MVI is a pretty rough one to try to shoehorn in, and I get the feeling that any generated results would be hideous at best. Wait MVI? What the hell happened to MVVM??
|
# ? Feb 26, 2022 22:55 |
|
|
# ? May 30, 2024 13:41 |
|
Can they quit hopping architectures for like 5 minutes
|
# ? Feb 26, 2022 23:06 |
|
FAT32 SHAMER posted:Wait MVI? What the hell happened to MVVM?? I can't find this now, maybe I've Mandela Effected myself but I could have sworn that the compose docs suggested using MVI instead of just MVVM. gently caress!
|
# ? Feb 26, 2022 23:07 |
|
Does compose not have something to wrap an existing activity or fragment into a compose hierarchy? AndroidView only works for views, which isn't that useful since the activity/fragment and its viewmodel do the useful work on views
|
# ? Mar 17, 2022 19:21 |
|
brand engager posted:Does compose not have something to wrap an existing activity or fragment into a compose hierarchy? AndroidView only works for views, which isn't that useful since the activity/fragment and its viewmodel do the useful work on views Your option is to “inflate” a composable in a fragment (I.e. use the fragment as the composable host which is then hosted by your activity) and nuke any viewbinding and xml associated with it, or go whole hog and use your activity to host composables and map their flow using the new jetpack composable navigation and nuke all of your fragments and refactor large swathes of your view models
|
# ? Mar 18, 2022 04:29 |
|
Oh also after using it ive decided using uris for deep linking is fuckin nice compared to the PendingIntentBuilder
|
# ? Mar 18, 2022 04:33 |
|
FAT32 SHAMER posted:Your option is to “inflate” a composable in a fragment (I.e. use the fragment as the composable host which is then hosted by your activity) and nuke any viewbinding and xml associated with it, or go whole hog and use your activity to host composables and map their flow using the new jetpack composable navigation and nuke all of your fragments and refactor large swathes of your view models That's the opposite of what I meant but it's not possible anyways. They just don't have an equivalent of UIViewControllerRepresentable
|
# ? Mar 18, 2022 05:47 |
|
Dipping my toes into mobile development, and I'm going with a ToDo app (I know, babby's first mobile app, but I am throwing in some kink by allowing nested items). Starting with Android and Kotlin (which are both new to me), I'm having an issue that I can't seem to make work, and it should be easy. I'm using a RecyclerView to display the todo items, and I can't for the life of me make the items clickable. Here's the relevant section of MainActivity: Kotlin code:
Kotlin code:
I worked from a Java example that had this as an adapter: Java code:
Edit: I just wrote a new Java project with the equivalent of the Kotlin above, and it works as expected. LongSack fucked around with this message at 19:36 on Jul 19, 2022 |
# ? Jul 19, 2022 17:22 |
|
I switched to jetpack compose recently specifically to get away from recyclerview,, if you're just learning then maybe it's better to stick to the latest paradigms?
|
# ? Jul 19, 2022 19:52 |
|
Vesi posted:I switched to jetpack compose recently specifically to get away from recyclerview,, if you're just learning then maybe it's better to stick to the latest paradigms? Probably. I’ve only just started the UI, so not much effort lost. Still bugs me that that Kotlin code doesn’t work when the Java equivalent works just fine.
|
# ? Jul 19, 2022 23:02 |
|
Try using val onClick: (dataToSendToHostFragment: Any) -> Unit Instead of the callback method, then call onClick.invoke(data) from the root of the viewholder Note: Any is whatever the object you’re returning from the adapter to the fragment is
|
# ? Jul 19, 2022 23:26 |
|
LongSack posted:Probably. I’ve only just started the UI, so not much effort lost. Still bugs me that that Kotlin code doesn’t work when the Java equivalent works just fine. Honestly, it SHOULD work the same, though there's probably some subtle bug that we all missed or which wasn't included here. You should be able to see the Java code that the Kotlin code transpiles to, which will at least make it easier to compare and see what if anything is different.
|
# ? Jul 19, 2022 23:57 |
|
FAT32 SHAMER posted:Try using If I understand you (and this is a huge if), I changed the ViewHolder to this: Kotlin code:
|
# ? Jul 20, 2022 13:23 |
|
Aren't you supposed to do all this setup in the onBind or whatever it's called? The recyclerView is probably messing with those viewHolders every time it recycles one so I wouldn't count on handlers set in a constructor
|
# ? Jul 20, 2022 21:05 |
|
Had to dig up our old app that still uses recyclerviews, we only did view inflating in onCreateViewHolder and we setup any handlers in onBindViewHolder
|
# ? Jul 20, 2022 21:14 |
|
brand engager posted:Had to dig up our old app that still uses recyclerviews, we only did view inflating in onCreateViewHolder and we setup any handlers in onBindViewHolder Except that the Java version works. It’s moot anyway since I took Vesi’s advice and switched to Compose. I like it, it reminds me of Blazor components and React functional components. The only thing I’m a little iffy on is that my MainActivity file is now at the size where if I were programming in C# I’d be looking to refactor some stuff out into separate classes. But since these are functions, I can’t really do that.
|
# ? Jul 20, 2022 21:25 |
|
Yeah you can, it’s kotlin, functions don’t need to be a class
|
# ? Jul 20, 2022 21:28 |
|
LongSack posted:Except that the Java version works. It probably shouldn't have
|
# ? Jul 20, 2022 21:35 |
|
smiling giraffe posted:Yeah you can, it’s kotlin, functions don’t need to be a class Interesting. I’m new to the language, so this is good info. Thanks.
|
# ? Jul 20, 2022 23:14 |
|
“be in a class”* even, but yeah, kotlin is great and apart from a few minor things, compose is great, and infinitely better than recyclerviews
|
# ? Jul 21, 2022 06:14 |
|
Question about state ... I'm storing the name of the most recent ToDoItemList in shared preferences and saving/retrieving the name in onPause and onResume: Kotlin code:
Kotlin code:
|
# ? Jul 28, 2022 16:00 |
|
You want to hold state in a viewmodel. This is an Android architecture component that is designed to persist as activities move through their lifecycle. View models typically expose their state using some implementation of the observable pattern, historically this has been livedata, but more recently StateFlow. This allows activities/fragments to observe and react to state when they are ready to do so. There should be plenty of good guides out there for getting setup with a viewmodel
|
# ? Jul 28, 2022 17:09 |
|
smiling giraffe posted:You want to hold state in a viewmodel. This is an Android architecture component that is designed to persist as activities move through their lifecycle. I was already using view models, but for some reason had the current list name stored in a separate variable. I moved it into the view model, and adjusted my onXxx methods and everything works still. Thanks!
|
# ? Jul 28, 2022 18:23 |
|
So, while new to Android and Kotlin, I'm trying to do things the "correct" way with dependency injection. I started using Koin but it was a real pain trying to figure out what combinations of import I needed to use where to get inject(). Switched to Hilt and while some things are easier, it's been a huge pain in its own right (I've lost track of the number of adjustments I've had to make to my gradle scripts). But I think I have it finally working, except for one thing. I want to inject my MainViewModel into my MainActivity. However, MainViewModel has its own dependencies: Kotlin code:
Kotlin code:
Fine, I can do that. Let's try this: Kotlin code:
Well, yeah, that's kinda the point. What am I doing wrong? If I have to instantiate the MainViewModel in my MainActivity, I'll also have to instantiate all of its dependencies and all of their dependencies, at which point it stops making sense to use DI.
|
# ? Jul 31, 2022 19:33 |
|
You still use "by viewmodels()" when using hilt.
|
# ? Jul 31, 2022 19:42 |
|
Volmarias posted:You still use "by viewmodels()" when using hilt. Thank you, that did the trick.
|
# ? Aug 1, 2022 19:28 |
|
OK Next problem. When using state, how does compose determine that the state has in fact changed and that a recomposition is necessary? Does it use the reference (i.e., address), a hash code function, or some other method? I've got my ToDo app to where it displays some mocked-up items, I can scroll them using LazyColumn, and there's a button to the left of the item text which is used to either complete on incomplete item, or to delete a completed / canceled one. I'm working on the first part - completing an item. The code works just fine, I can step through in the debugger and see that the state of the item is being updated in my repository (currently memory-based) and in the state in my view model, however the item on the screen never gets updated. Weirdly, however, if I scroll the item off the page then back on, it does get displayed as expected (with the title in strikethrough). So something is happening that is causing the item not to be recomposed when the completed state changes, but the state is in fact changed as can be seen when I scroll it off and back on, which forces a recompose. The structure is like this: MainActivity -> RootPage -> ItemList -> (LazyColumn of) ItemCard Some relevant code ItemState Kotlin code:
Kotlin code:
Kotlin code:
Kotlin code:
Kotlin code:
Kotlin code:
|
# ? Aug 3, 2022 20:18 |
|
I think you want your viewmodel to expose your UI state in a StateFlow, which is collected in your activity when its in the appropriate lifecycle state. See: https://developer.android.com/kotlin/flow/stateflow-and-sharedflow#stateflow I think the State class you are using in the viewmodel only causes recomposition within the context of a composable function. More generally you shouldn't need to inject your repo into the activity and pass it to the composables. Giving the Activity the Repo you're letting it know to much, the Activity should just be like: "here is some ui state from the viewmodel that I will observe. when a button is clicked i will tell the viewmodel it happened". Then it's the viewmodels job to decide how that button click should result in a change of state. Also not sure why you are wrapping ToDoItem in a MutableState
|
# ? Aug 3, 2022 21:16 |
|
smiling giraffe posted:I think you want your viewmodel to expose your UI state in a StateFlow, which is collected in your activity when its in the appropriate lifecycle state. See: https://developer.android.com/kotlin/flow/stateflow-and-sharedflow#stateflow Thanks, I’ll check that out tomorrow quote:Also not sure why you are wrapping ToDoItem in a MutableState Originally it wasn’t, it was just something i tried to see if that would correct the problem. EDIT: I feel like when I first started WPF and didn’t understand data binding. My first version of my character portfolio app literally copied data from the DTO objects to the screen and back. Then one day it just “clicked”. I hope that this happens here too. LongSack fucked around with this message at 23:18 on Aug 3, 2022 |
# ? Aug 3, 2022 23:15 |
|
Here’s a comment I saw a while ago that really resonated with me re: keeping state in the viewmodel/MVI in general: https://www.reddit.com/r/mAndroidDe...ossmf&context=3 I’m on mobile otherwise I’d try to embed the quote with the codeblocks
|
# ? Aug 3, 2022 23:52 |
|
smiling giraffe posted:I think you want your viewmodel to expose your UI state in a StateFlow, which is collected in your activity when its in the appropriate lifecycle state. See: https://developer.android.com/kotlin/flow/stateflow-and-sharedflow#stateflow OK based on that page, I changed the state to a (Mutable)StateFlow. Making that change alone didn't change anything. Then I noticed the part about the change in the onCreate method, so I added that: Kotlin code:
|
# ? Aug 4, 2022 15:01 |
|
this spot where you're making a state object further down in the composable is gonna create a new state every time the library checks if it needs to recompose, that's gonna cause some weird issuesKotlin code:
Kotlin code:
|
# ? Aug 4, 2022 15:46 |
|
Also that StateFlow class isn't a Compose state, it just happens to have use state in the name. I don't think it'll cause recomposing like the actual androidx.compose.runtime.State type will
|
# ? Aug 4, 2022 16:08 |
|
brand engager posted:this spot where you're making a state object further down in the composable is gonna create a new state every time the library checks if it needs to recompose, that's gonna cause some weird issues The state object is created in the viewmodel which is injected into the composable, and should be scoped to the lifetime of the composable quote:what is this function? That's where the LazyColumn gets its items from The book I worked through prior to starting this project(Kickstart Modern Android Development with Jetpack and Kotlin, here) develops an app using viewmodels and state and it simply uses a MutableState<T> object (with a public State<T> getter) and it works just by using copy() on it as the state changes, and it seems to work just fine.
|
# ? Aug 4, 2022 16:50 |
|
LongSack posted:OK based on that page, I changed the state to a (Mutable)StateFlow. Making that change alone didn't change anything. Then I noticed the part about the change in the onCreate method, so I added that: try this: nm smiling giraffe fucked around with this message at 17:32 on Aug 4, 2022 |
# ? Aug 4, 2022 17:06 |
|
LongSack posted:The state object is created in the viewmodel which is injected into the composable, and should be scoped to the lifetime of the composable You're also making one in the spot I quoted though which is a problem for reasons already mentioned LongSack posted:That's where the LazyColumn gets its items from Oh ok thought you had created your own forEach()
|
# ? Aug 4, 2022 17:18 |
|
brand engager posted:You're also making one in the spot I quoted though which is a problem for reasons already mentioned Oh, that part is gone. I had put it in to see if it would help, but it didn't make any difference, so I removed it. It just passes the item now Edit: To expand on that a bit (as to why I tried that), when doing data binding in WPF everything that the UI binds to is observable. So if I have a list of Foo, not only is the collection observable (using ObservableCollection or ObservableDictionary), but the Foo model is itself completely observable, something like: C# code:
LongSack fucked around with this message at 17:55 on Aug 4, 2022 |
# ? Aug 4, 2022 17:48 |
|
ok try this:Kotlin code:
|
# ? Aug 4, 2022 18:21 |
|
smiling giraffe posted:ok try this: Wouldn’t it be lifecycle aware by way of the viewmodel? All it needs to know is if it’s active or not, and it’ll flow as soon as everything comes back after an onResume or w/e
|
# ? Aug 4, 2022 18:23 |
|
|
# ? May 30, 2024 13:41 |
|
Usually I do code reviews in android studio, and piecing the whole thing together from different posts is kinda a pain. Think you're gonna have to figure out the issue yourself lol
|
# ? Aug 4, 2022 18:38 |