Actually, you don’t need a Context
proper. What you need is a reference to a class that extends SQLiteOpenHelper
.
Let’s say, a class Database
:
public class Database extends SQLiteOpenHelper {
...
}
This class, in turn, needs a Context
.
There are several different ways you pass a reference to this Database
for your model. You can create a method static
in your class Application
that returns to you an instance of the class Database
.
public class MyApplication extends Application {
private static MyApplication sInstance;
@Override
public void onCreate() {
super.onCreate();
sInstance = this;
}
public static Database getDatabase() {
return new Database(getContext());
}
public static Context getContext() {
return sInstance.getApplicationContext();
}
}
So just do it in your Model (or Presenter and send it to the Model):
MyApplication.getDatabase();
Although it works I don’t really like this approach. I don’t think it’s right to do it in the Application class.
So you could have a class, say: Injection
. Where you perform "DI in hand".
public final class Injection {
private Injection() {
throw new IllegalStateException(Injection.class.getSimpleName() + " cannot be instantiated!");
}
public static Database provideDatabase() {
return new Database(MyApplication.getContext());
}
}
Another alternative is if you use Dagger, for example, let it do the class automatic dependency injection Database
in his Model.
I read about the solution of the application, and they say it is bad because it disturbs the test, and it is a bit tricky (by what they say)... I also can not use Dagger
– felipe.rce
If I send the Database class to the presenter, am I violating the MVP as well? Not only sqlite, but there are other things that use context, like sharedpreference...
– felipe.rce
@Elipe.rce Fetch the
Context
ofApplication
using the classInjection
is not gambiarra. Often we need to do this because we need something that exists throughout the application. That’s why it’s where we start some libs, like Dagger. And that doesn’t make Dagger gambiarra. You should only know how to use at the right times.– Luiz
is that many responses in stackoverflow point out that keeping the context static in the application is not a good solution (see comments): https://stackoverflow.com/questions/39100105/need-context-in-model-in-mvp and comments pointing out that it is wrong
– felipe.rce
@Elipe.rce On the
SharedPreferences
: what we need to make clear is this: you don’t need theContext
for these tasks and should not pass it to the Model. Create an abstraction for the preferences and pass the instance of that class. Again, you can create it at Injection by recovering theContext
ofApplication
. Or even create it in thePresenter
, passing theContext
for the classInjection
need not seek theApplication
.– Luiz
@Felipe.rce Yes. If you don’t want to go down this path, pass Context to Presenter and Presenter to Injection. That way you don’t need to pass it to the Model and also didn’t recover from the Application.
– Luiz
you speak pass the context through the interface or the constructor?
– felipe.rce
Leave this method only
Context getContext();
in your View. So you can call it the Presenter and create the classDatabase
, for example. Or you can even send the classDatabase
already created by the builder ofPresenter
(maid inView
using the `Injection).– Luiz
I found the idea of sending the Database class more interesting, because then I won’t be sending something from Android to the presenter
– felipe.rce
@Felipe.rce Ok, it’s a good approach. But don’t install it directly in the View. Abstraction for a class
Injection
(or something like that) and you’ll have a better and more decoupled implementation. ;)– Luiz