https://kotlinlang.org logo
#android-architecture
Title
# android-architecture
n

Nick

10/01/2020, 2:22 PM
We have a custom view that is used in a lot of places. We want to tie this to a viewmodel and keep all the business logic there. A coworker suggested just passing in the ViewModel and lifecycle owner to the custom view and then observe on the properties. This doesn’t feel right. What do you guys do?
s

streetsofboston

10/01/2020, 2:32 PM
Don’t make a (custom)
View
dependent on a ViewModel… Instead, think about how Fragments and Activities handle this. A Fragment or Activity receive a ViewModel and a View as input/dependency and this Fragment/Activity then observes properties on the ViewModel and manipulates the View accordingly.
Copy code
View ------+
           +--> Fragment/Activity
ViewModel -+
Make a similar type of class (a ‘controller’?) that will take (or get injected) a custom View and your custom-view related ViewModel like a Fragment or Activity.
Copy code
MyCustomView      --+
                    +--> MyCustomController
MyCustomViewModel --+
👍 1
a

allan.conda

10/01/2020, 2:36 PM
This doesn’t feel right.
What makes you feel so?
s

streetsofboston

10/01/2020, 2:39 PM
Copy code
class SomeActivity : AppCompatActivity() {
    ...
    
    val myCustomController: MyCustomController by lazy {
        MyCustomController(findViewById(R.id.my_custom_view), MyCustomViewModel())
    }
    ...
}
You could finagle the creation of the MyCustomController and its dependencies (MyCustomView and MyCustomViewModel) through dependency injection (dagger/koin/etc), if you want to remove some boiler plate.
@allan.conda You should avoid making an Android View being dependent on a ViewModel. E.g TextViews, RecyclerViews, any other View don’t rely on ViewModels, including your own custom Views.
a

allan.conda

10/01/2020, 2:49 PM
Why not? 🙂 I can imagine a full Custom View approach using libraries such as Conductor. Where would you put the ViewModel in such case?
Their idea doesn’t break the MVVM pattern
s

streetsofboston

10/01/2020, 2:57 PM
You put the ViewModel in a controller (like the example ‘MyCustomController’ above). True, it doesn’t break the MVVM pattern. But makes MyCustomView dependent on MyCustomViewModel which is not necessary, and it would break the rendering of the custom view in the IDE’s layout-editor (the layout-editor wouldn’t know how to provide an instance of MyCustomViewModel).
Instead of
class MyCustomView(private val viewModel: MyCustomViewModel): View() {...}
it would be
class MyCustomView : View() {…}
and a
class MyCustomController(private val view: MyCustomView, private val viewModel: MyCustomViewModel)
where the MyCustomController plays the same role as a Fragment or Activity with respect to hooking up a ViewModel to a View. You could use dagger/koin to reduce the boilerplate instantiations of MyCustomControllers.
g

gildor

10/01/2020, 3:06 PM
Using completely custom views as replacement for fragment/activity is a valid thing, but it requires quite a lot of custom logic and essentially own framework, and very easy to implement it in a wrong way It's more flexible approach I. Theory, but it easy becomes a huge mess. We used to use fully custom views as controller, but eventually decide that it doesn't worth it, and now it's our biggest legacy, it painful every time to touch this code, none of new features of androidx (lifecycle, viewmodels, backstack dispatchers) works there
j

Joost Klitsie

10/01/2020, 3:17 PM
@Nick would it be possible to refactor this view to become a fragment containing the view?
n

Nick

10/01/2020, 3:20 PM
@Joost Klitsie That could work too. But I always feel like fragments contain so much overhead with the extra lifecycle.
s

streetsofboston

10/01/2020, 3:36 PM
@Nick Yup, a lot of overhead. That is where that ‘controller’ type of class comes in, like a very very lightweight fragment 🙂
n

Nick

10/01/2020, 3:36 PM
Are there any examples that you’ve seen online that show what you describe?
g

gildor

10/01/2020, 3:39 PM
the situtation with fragments lifecycle may be improved, there. are plans to follow lifecycle of view (so no more detached fragment). So, when it will happen, this “lightweight controller view” becomes “heavyweight” 🤷
I mean, yeah, lifecycle of fragment is more complicated, but View API is kinda terrible itself (3 required constructors, attributes, injection is hard), and if you also have fragments it become problem. All this can be mitigate, but I really think it makes sense only if you know what you are doing
n

Nick

10/01/2020, 3:47 PM
The majority of our crashes and problems comes from lifecycle issues related to fragments. I want to avoid them if I can.
a

allan.conda

10/01/2020, 3:48 PM
but it requires quite a lot of custom logic and essentially own framework,
I know 🙂 , that’s why I mentioned using something like Conductor to facilitate this, because this wasn’t how the Android Views were originally designed for. Additionally, Jetpack Compose is just around the corner. It doesn’t need Fragments or multiple Activities, and you can provide the viewModel from the top level Composable function
You put the ViewModel in a controller
That could work also, but that’s no longer simple MVVM. It’s MVVM+Controller.
g

gildor

10/01/2020, 3:58 PM
The majority of our crashes and problems comes from lifecycle issues related to fragments. I want to avoid them if I can.
Really? what kind crashes? i
n

Nick

10/01/2020, 3:58 PM
so @streetsofboston, the controller will take the viewmodel as a param (that’s already created using the fragments lifecycleowner), and inside the controller i’d observe on the properties?
g

gildor

10/01/2020, 3:59 PM
that’s why I mentioned using something like Conductor
I’m not a big fan of conductor, for me it looks that they took all bad things from fragments, but yeah, made lifecycle more simple
a

allan.conda

10/01/2020, 4:00 PM
@Nick there was a huge refactoring of Fragments, and part of that is fixing lifecycle issues and trying to align with the Activities’ lifecycle. You can consider using them again. https://medium.com/androiddevelopers/fragments-rebuilding-the-internals-61913f8bf48e Alternatively, LifecycleOwner is supposed to be a simpler way to have lifecycle-aware classes as well. I asked why your colleague’s idea doesn’t feel right, since I think there is a case specific to your project that make that a bad idea. 🙂 As you can see here everyone has their opinions based from their experiences, so I guess that answers your question as you were simply asking how the others are doing. There is no right single answer I think
👍 1
☝️ 1
g

gildor

10/01/2020, 4:00 PM
I just want to point out, that using conductor it’s not the same as using custom view for controller, it’s essentially the same approach as use fragments, just different implementation
a

allan.conda

10/01/2020, 4:00 PM
I’m not a big fan of conductor, for me it looks that they take all bad things from fragments, but yeah, make lifecycle more simple
me neither 😄 I don’t like to depend on 3rd party libraries for something so important unless it’s really mainstream
And of course, controller is a responsibility, it’s not tied to any library nor required by MVVM. It’s something you could separate further from the MVVM to adhere to SRP. Same as having other patterns such as UseCases, repositories
f

Fatih

10/01/2020, 5:03 PM
Sounds like MVP not MVVM.
87 Views