Hello, I use Kotlin in my Android App. I'm a bit c...
# android
b
Hello, I use Kotlin in my Android App. I'm a bit confused about the Companion Object in an Activity Class. Can the companion object be used as an Activity State? For example, I have an activity with a MutableListOf<Item> and I have set it in companion object. Is it a good practice to update the list of this class from other classes?
🚫 6
c
Mutating instance state in a companion object (which is across instances) will lead to race conditions (at worst) and Very Confusing Behaviour/Code (at best). Think of the companion object as equivalent to Java static methods (largely that’s what they map to in the JVM), used for operations at the class (not instance) level. A common pattern is to have companion object functions that create instances, for example.
b
@Chris Lee So It's not a good idea to store activity's state in companion object. What would be a better approach in order to update an Activity's state? For example, I have a list named "Contacts" (for chat) in Chat Activity. This list should be updated even if user is not on this activity. What do you suggest? Is it better to use an object that will be accessible to other classes too?
c
not familiar with Android so not able to provide specifics there. From a general perspective solutions would include: • getting a reference to that instance and calling methods on it (not ideal, as it increases coupling); • sending some kind of ‘state updated’ event that the activity can react to • maintaining that state elsewhere that the activity can pull from (instead of maintaining the state itself) Hopefully someone with Android-fu can turn this into meaningful specifics 😉
b
Okay thank you Chris
👍 1
r
Android architecture is a big topic but would definitely recommend you start with the official guide: https://developer.android.com/topic/architecture
b
@Robert Williams I’m coming from web dev so I used Rekotlin. It’s a redux implementation in Kotlin for state management, but it’s a bit buggy. So in order to handle the app state (lists etc that must be accessible in all app activities) is to create a Singleton?
How do you handle the internal state in memory of the app? For example, the user logs in and fetch all user data (eg. Name, favorites list etc.) where do you store them?
c
Generally-speaking, the Androidx ViewModel was created to be that thing that holds state for your screen. Initially, there’s not a whole lot to it other than moving the variables you used to manage in the
Activity
to the
ViewModel
, but there’s a lot more benefit when you use it as part of an Architecture Design Pattern like MVVM or MVI. ViewModels specifically work with in-memory data, and it should generally be considered ephemeral. That is, the data stored in your ViewModel sticks around for only 1 app session, and you’d need to reload it the next time the user opens the app (or on other conditions that are shorter than the entire session, depending on your app’s navigation). For anything that needs to be persisted longer than the lifetime of the ViewModel (such as across app launches), you’d need to store it in a persistent way, such as with DataStore or Room
b
@Casey Brooks for persistent storage I use Realm. I use a list in companion object of Activity (ContactsActivity) named contacts. When a new message received I use EventBus (green robot author in GitHub) to pass the msg to the contacts list even if I’m not in the ContactsActivity. Will this lead to memory leak?
c
That library has been known as an anti-pattern for quite some time. What you should do instead is: 1. Create a
ContactsViewModel
and use the Android facilities to get an instance of it in your
ContactsActivity
2. Observe your Realm query as a
Flow
within the ViewModel’s
viewModelScope
(see docs). Whenever the query updates, save the query results somewhere within the ViewModel such as a
StateFlow
3. Your
ContactsActivity
should collect the ViewModel’s
StateFlow
from within its
lifecycleScope
. Thus, the whole pipeline becomes “Realm > ViewModel > Activity”, but everything is being done safely and is managed, such that if you leave the Activity you’re no longer wasting resources or leaking memory from db subscriptions that are not actively visible on the screen
b
@Casey Brooks I want to use realm only for messages storage of conversation not for contacts list. So a better approach is to use ViewModel in order to handle state in all activities than using singletons with event bus etc?
c
Yes, like I mentioned, that event bus library has been known for many years as an anti-pattern. It was created long before the ViewModels existed and before we really knew how data needed to be managed and sent throughout the application. Android lifecycles are really complex and difficult to work with, especially compared to webpages, and if you rely on unsafe mechanisms like singletons and EventBus, you’re going to get a lot of really strange issues of things like missing data, random crashes, etc., that are very difficult to debug. It’s highly recommended to use ViewModels and follow the best-practices outlined in the Android architecture guide. These architecture recommendations exist because of the problems inherent to the singletons and Event Bus-type architectures that plagued Android apps for many years
👌 1
r
There's nothing terribly wrong with Singletons for holding ephemeral state as long as they are: • in the data layer • accessed with interfaces and DI • observable and reactive • abstracted by ViewModel
c
Right. As with anything, once you know how to do things properly, then you start to know when it makes sense to break out of that pattern. But it’s better to start with ViewModels and proper Architecture Components than with Singletons
b
I use this library for state management-> https://github.com/ReKotlin/ReKotlin what do you think?
c
I haven’t used that library personally, but MVI is definitely my recommended pattern if you’re comfortable with that pattern. MVI definitely requires a different way of thinking about developing your UI compared to traditional MVC and similar patterns, but if you’re coming from a Web background then it sounds like you’re comfortable with it already. I’m the maintainer of Ballast, which takes the MVI concept and makes it a little more robust to handle additional use-cases like subscribing to Flows and sending one-off events. Also, unlike ReKotlin (from what I can tell), Ballast offers out-of-the-box support for managing the state in ViewModels so that you’re not holding them in singletons which could leak memory if not managed properly. There’s plenty of documentation on the general usage and it’s android integration, and you can join us over at #ballast if you have any questions about it
m
there’s a lot of MVI library, agreed with Casey. 1. #orbit-mvi 2. recent MVI author @Hannes also release state machine mvi-like in https://github.com/freeletics/FlowRedux