I was wondering if someone could either point me to documentation to / clarify when to create or destroy a room database instance. Also how you would effectively open / close it ?
If I have a RoomDatabase object that gets injected via dagger to a presenter is that cool and then I just access various Daos? I'm worried about having the object lingering and taking up memory.
Instead of Injecting the RoomDatabase into your presenter you could Inject a DataManager Singleton class.
This DataManager can hold your WeakReferences to your DAOs . Based on when you try to access the data, first check if you have it in memory pass it on to the presenter, if not you can then Lazily access the RoomDB to load data into memory and then pass on to the presenter.
In this way, there is a Single Source of Truth that accesses/manages your data.
Related
Currently, I have a database manager class that handles all operations to the database like this:
class DatabaseManager(val context: Context) {
private val db = Firebase.firestore
//Other functions, etc.
}
It makes use of the context passed in by different activities to perform functions to the database. The thing is, every single activity that requires database functions have to instantiate this manager class first, then call the functions. I would like to make use of the Singelton design pattern to make it such that all the activities will only use a single instance of the class. I believe kotlin's objects can do this, however I also need to be able to pass in the context of the activities into this manager class. Any assistance is appreciated, thank you!
I would recommend not doing that. The problem with Singletons is that they make code hard to test, you can't fake out the database. And for a database this is a particularly bad problem, as setting up all the right fake data can be painful. Instead, take a look at injection. It can do the same thing (make a single instance shared between everyone who needs it), but it manages that global state rather than having the classes themselves manage it via a static reference, passing it in (generally via the constructor) to whoever needs it. This makes it easy to provide an alternative or mock database when needed for testing. Injection used to be a bit painful to set up, but Hilt makes it a lot easier these days.
I am building an application in Android with multiple activities. I have a list of an object of type TodoItem that I get from a collection in Firestore database, and I need to access the list from more than one activity to make changes and updates to the list.
To do that, I thought about saving the list in the Application scope (is it a good idea?). For this reason, I created a class MyApplication extends Application (and added it to the Manifest file).
Instead of just adding the list as a class field of MyApplication I thought that maybe I should create a class named DataManager that will hold application-wide information such as my list of TodoItems (and here I ask again: is it a good idea? or maybe there is a better solution?).
At this point I am trying to decide what is a better approach to create and save the DataManager class:
One idea is to make DataManager a Singleton class and save it as a class field of MyApplication. This way, the activities will be able to get the instance of the class using DataManager.getInstance() without the need to get it from the application class with a getter method. In this approach, I will have to create the instance of DataManager and init the field of the application with it in the OnCreate() method of the application.
The second idea is to make it a non-singleton, add DataManager field to MyApplication, and create a getter named getDataManager() in the application class. The getter will check if the field is null (i.e. already initialized or not) and will create a new instance correspondingly. This way, the activities will get the instance using ((MyApplication) getApplication()).getDataManager().
I would like to hear what do you think about my approaches to solve the problem, and if you have any other suggestions or other ways to improve my suggested design.
A nice way when your data source is simple. You can create a singleton class to hold and manage data, including read and write from the singleton.
When you want to use complex data, you can store it to your device disk rather than memory. Android application support you to store your data with file, database, or key-value preference. As for your case, you can use database to store your todolist. Android support sqlite for these work, and we have official orm library called room.
raw sqlite: https://developer.android.com/training/data-storage/sqlite
room library: https://developer.android.com/topic/libraries/architecture/room
I have one Activity and i have created one View-model for it. I have created different classes like
UiUtil( show, hide view, hide key board ), Network layer , Data Base layer, AppUtil( for common functionality like Collection check, String validation, Date Conversion etc)
My question is, In MVVM design pattern is Activity can use these utility classes directly or it needs to use these classes via View-model, if it via view model then in the view-model i have to write a method that just call utility classes method . like below TimeDateManager is utility class used in view-model
class HomeViewModel: BaseViewModel()
{
fun prepareTimeAmPmToDisplay(context: Context, alarm: Alarm): String
{
return TimeDateManager.prepareTimeAmPmToDisplay(context, alarm)
}
}
Architectures are not obligatory, they are recommendational, thus you can change their usage in quite wide range. The only stopper should be a common sense(if it is present of course).
In this particular case the usage of utility class inside an Activity maybe ok, based on your ViewModel construction and its way of communication with View(read Activity).
For example if you have some LiveData that sends some kind of event(for ex. data loaded from backend or alarm trigger) inside your ViewModel and your View listens to it, I think it is ok to use util classes inside an Observer in Activity. Especially if this utils method doesn't depend on any ViewModel or Repository data. The direct utils usage in Activity is not limited by this usecase, though - there are plenty of others.
I understand that this may be an unpopular opinion in modern time of "clean approach" but I believe that this "clean approach" sometimes complicates stuff where it shouldn't, thus if mixing things a bit does not brake overall architecture but rather makes some thing more readable and easy to maintain - I would go for it.
Hope it helps.
My approach toward MVVM is simple, ViewModel is responsible for business logic, dealing with repositories (Network, Database, etc.) and all of the non-UI codes preparing the required data for UI, just like the documentation:
A ViewModel object provides the data for a specific UI component, such as a fragment or activity, and contains data-handling business logic to communicate with the model. For example, the ViewModel can call other components to load the data, and it can forward user requests to modify the data. The ViewModel doesn't know about UI components, so it isn't affected by configuration changes, such as recreating an activity when rotating the device.
On the other hand, ViewModels should not store a context (ApplicationContext is exceptional) and it's preferred that they do not use android APIs at all, so they become more testable (especially in the case on pure unit tests).
Also we are recommended to make use of LiveData in ViewModels and the UI has to observe the LiveData. For example, in onCreate of your Activity, you will call loadMainContent() method from VM, it calls getMainContent(page=1) from repository, and the repository will decide to load data from DB or network, and the result will be set on a LiveData were the View is listening for changes.
TL;DR
Sometimes it's even better to call these utilities from View rather than the VM. I'm pretty sure about your UiUtil also I think TimeDateManager is more view related rather than logic related. In addition, Network and DB layers are more efficient if called through a repository (which is responsible for caching, etc.) and VM can use that repo.
I have two questions regarding Android memory optimization:
Which is more memory expensive in Android, to use a global field or local field?
Dependency injection with dagger- is it better to use objects (services, view models.. ) in an #applicationScope or #activityScope
Local variables are stored on the stack and when the function is finished, the local variables are gone as well. Global variables always exist and use their memory during the life time of the entire program. Its always better to declare a variable nearest to where it's used. So local variables are to be preferred.
About dagger 2 custom scope, the instances scoped in #ApplicationScope lives as long as Application object and #ActivityScope keeps references as long as Activity exists. So the objects should be under the scopes in which it is required. If it is required only in the activity or its hosted fragments use #ActivityScope or if you need the singleton object in an application scope define it #ApplicationScope.
Hope this helped you.
I am new to android MVP pattern and working on my project i have some basic problem related to Android Context in the presenter. Although there are many answers related to this but i didn't get a perfect one which can solve my problem.
I have following queries:
how to access shared preferences inside presenter.
how to access other system services inside presenter.
if i am working on SQLite Databases then during any transaction in my database which is done by call from presenter to my SQLite Helper class need context to access database.
If i will pass my activity context in presenter then it will a problem during unit testing, also it is a violation according to MVP Format.
I need a perfect solution so that my code quality is not degraded.
Note: I dont want to use dagger tool so the answer should be dagger independent
In MVP you dont use Context or anything else from the Android SDK/Framework in the Presenter (P) layer! This layer is for anything else than Android related stuff.
1) how to access shared preferences inside presenter.
You don't. If you need a value from a SharedPrefences in the Presenter then you could pass the value to the Presenter via a method call.
Example:
class MainActivity{
String birthday = SharedPrefence.getString(..);
presenter.setSavedBirtday(birthday);
}
2) how to access other system services inside presenter.
As metioned before; You don't acesss System services in the Presenter.
What you can do is call the a System Service from the Presenter.
Example with Vibrator:
1 - Create an interface:
interface OnSystemServiceCaller{
onVibratorCall();
}
2 - Implement it in a Activity
class MainActivity implements OnSystemServiceCaller{
#Override
onVibratorCall(){
Vibrator v = (Vibrator) getSystemService(VIBRATOR);
v.vibrate(50);
}
}
3 - Call from presenter
class Presenter{
OnSystemServiceCaller listener;
public void ifButtonClicked(){
listener.onVibrateCall();
}
}
3) if i am working on SQLite Databases then during any transaction in my database which is done by call from presenter to my SQLite Helper class need context to access database.
Some wont like this answers other will, this is just a suggestion.
You can access your SQLite by using a global ApplicationContext() in your app class (Class that extend Application; see how here since your SQLlite is global for the whole app and not just a particular Activity And when you need to pass data from SQLite to a Activity then you pass it first to the Presenter and from Presenter to your Activity the same way we send a call to our Vibrator method