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
Related
I'm very new to android development and struggling to find this answer. Is it possible to share the same instance of a data class across all my view models?
Currently when my app first starts, I'm fetching my user's app preferences from a Firestore DB and instantiating a data class instance I have defined to hold all user preferences. I want to have all my view models to have access to the user preferences without every view model having to make the Firestore DB call and creating its own data class instance. Is it possible to share the same instance of a data class between all of my view models?
I could use dagger hilt to to fetch the preferences from Firestore, create my data class instance, and provide that as a dependency of injection....but if a user updates their preferences after loading the app then those updates won't reflect in the data class instance that is injected via dagger hilt, correct?
Admittedly I might be going about this the wrong way. I'm ultimately trying to understand what the best way to share my app preferences that are stored in an external DB to all of my view models.
After getting the data in your viewModel , initialize the related viewmodel in your fragment as activityViewModel as below;
val shareViewModel by activityViewModels<ShareViewModel>()
If you use it in your activity just set this for owner parameter as below;
val shareViewModel = ViewModelProvider(this)[ShareViewModel::class.java]
It provides you sharing data across your app
Moreover, check this codelab https://developer.android.com/codelabs/basic-android-kotlin-training-shared-viewmodel
I need a variable accessed and updated by two or more services or activities. I am thinking of using interface. A class that implements that interface to be initialized in Base Application class or via hilt. I am not entirely sure how to do that.
Is this possible and if so, is this good idea?
Can I use any other way to pass variable from service to service or activity to service?
Possible psuedoCode for idea.
interface foo(){
variable a
fun setA(var : p)
}
class JustAClass: foo{
variable a;
fun setA(var : p){
a = p
}
}
BaseApp(): Application(){
JustAClass jac = JustAClass();
}
activityA(){
BaseApp.jac.setA(99)
}
serviceB(){
variable c = BaseApp.jac.a
}
Yes, you could do it the way you describe, but there are a few easier ways...
You can use a Singleton. In Kotlin, any Object is automatically a statically accessible Singleton. So, something like this:
object SharedData{
var item1 = "test"
var item2 = false
}
can be accessed anywhere in your app by using SharedData.item1 or SharedData.item2. You can also make those variables into LiveData or Kotlin Flow if you want to post updates and observe them between activities/services/etc.
You can also store your data in SharedPreferences. It'll provide more permanent storage that will survive app restarts, but it reads and writes data to internal storage, so you need to deal with IO overhead.
You can also store your data in other permament data structures, like a Room Database, but I think that would be overkill for just communicating between processes.
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 am fairly new to android and after reading a book and taking alot of tutorials i am about to create my first "real" app.
My question is rather simple does: Is the mediator design pattern still a good choice when designing android apps?
If yes is there any design patterns you should avoid when programming android apps?
if no is there any substitude to the mediator pattern you could use to have a collection of your instances of the different objects?
I suggest creating a model class (let's call it MyModel) and creating object of this class in Application.onCreate (not Activity.onCreate).
After that adding getter for that, so you can get this model from any Activity or Service like this:
MyApplication app = (MyApplication) getApplication();
MyModel model = app.getMyModel();
User user = model.getCurrentUser();
etc.
Also creating BaseActivity class can save you typing if you create method there protected MyModel getModel() which returns model from the first 2 lines of the code above.
Edit:
You need to create a class that extends Application and register this class in AndroidManifest.xml.
This is how: https://stackoverflow.com/a/2929927/2183804
Edit (about singleton):
It is said to be an anti-pattern (not only on Android). In Android I have seen people ending with singleton with accessor like MySingleton.getInstance(Context), because they needed Context anyway, e.g. for SharedPrefs or DB access. This is what Application is for, so there is no need to create additional, hackish entity, which could be used in a wrong way: MySingleton.getInstance(null) from a place where there is no Context available. This could lead to NPE after process is killed and restarted.