Is there a way to get the current Context instance inside a static method?
I'm looking for that way because I hate saving the 'Context' instance each time it changes.
Do this:
In the Android Manifest file, declare the following.
<application android:name="com.xyz.MyApplication">
</application>
Then write the class:
public class MyApplication extends Application {
private static Context context;
public void onCreate() {
super.onCreate();
MyApplication.context = getApplicationContext();
}
public static Context getAppContext() {
return MyApplication.context;
}
}
Now everywhere call MyApplication.getAppContext() to get your application context statically.
The majority of apps that want a convenient method to get the application context create their own class which extends android.app.Application.
GUIDE
You can accomplish this by first creating a class in your project like the following:
import android.app.Application;
import android.content.Context;
public class App extends Application {
private static Application sApplication;
public static Application getApplication() {
return sApplication;
}
public static Context getContext() {
return getApplication().getApplicationContext();
}
#Override
public void onCreate() {
super.onCreate();
sApplication = this;
}
}
Then, in your AndroidManifest you should specify the name of your class in the AndroidManifest.xml’s tag:
<application
...
android:name="com.example.App" >
...
</application>
You can then retrieve the application context in any static method using the following:
public static void someMethod() {
Context context = App.getContext();
}
WARNING
Before adding something like the above to your project you should consider what the documentation says:
There is normally no need to subclass Application. In most situation,
static singletons can provide the same functionality in a more modular
way. If your singleton needs a global context (for example to register
broadcast receivers), the function to retrieve it can be given a
Context which internally uses Context.getApplicationContext() when
first constructing the singleton.
REFLECTION
There is also another way to get the application context using reflection. Reflection is often looked down upon in Android and I personally think this should not be used in production.
To retrieve the application context we must invoke a method on a hidden class (ActivityThread) which has been available since API 1:
public static Application getApplicationUsingReflection() throws Exception {
return (Application) Class.forName("android.app.ActivityThread")
.getMethod("currentApplication").invoke(null, (Object[]) null);
}
There is one more hidden class (AppGlobals) which provides a way to get the application context in a static way. It gets the context using ActivityThread so there really is no difference between the following method and the one posted above:
public static Application getApplicationUsingReflection() throws Exception {
return (Application) Class.forName("android.app.AppGlobals")
.getMethod("getInitialApplication").invoke(null, (Object[]) null);
}
Happy coding!
Assuming we're talking about getting the Application Context, I implemented it as suggested by #Rohit Ghatol extending Application. What happened then, it's that there's no guarantee that the context retrieved in such a way will always be non-null. At the time you need it, it's usually because you want to initialize an helper, or get a resource, that you cannot delay in time; handling the null case will not help you.
So I understood I was basically fighting against the Android architecture, as stated in the docs
Note: There is normally no need to subclass Application. In most situations, static singletons can provide the same functionality in a more modular way. If your singleton needs a global context (for example to register broadcast receivers), include Context.getApplicationContext() as a Context argument when invoking your singleton's getInstance() method.
and explained by Dianne Hackborn
The only reason Application exists as something you can derive from is because during the pre-1.0 development one of our application developers was continually bugging me about needing to have a top-level application object they can derive from so they could have a more "normal" to them application model, and I eventually gave in.
I will forever regret giving in on that one. :)
She is also suggesting the solution to this problem:
If what you want is some global state that can be shared across different parts of your app, use a singleton. [...] And this leads more naturally to how you should be managing these things -- initializing them on demand.
so what I did was getting rid of extending Application, and pass the context directly to the singleton helper's getInstance(), while saving a reference to the application context in the private constructor:
private static MyHelper instance;
private final Context mContext;
private MyHelper(#NonNull Context context) {
mContext = context.getApplicationContext();
}
public static MyHelper getInstance(#NonNull Context context) {
synchronized(MyHelper.class) {
if (instance == null) {
instance = new MyHelper(context);
}
return instance;
}
}
the caller will then pass a local context to the helper:
Helper.getInstance(myCtx).doSomething();
So, to answer this question properly: there are ways to access the Application Context statically, but they all should be discouraged, and you should prefer passing a local context to the singleton's getInstance().
For anyone interested, you can read a more detailed version at fwd blog
No, I don't think there is. Unfortunately, you're stuck calling getApplicationContext() from Activity or one of the other subclasses of Context. Also, this question is somewhat related.
Here is an undocumented way to get an Application (which is a Context) from anywhere in the UI thread. It relies on the hidden static method ActivityThread.currentApplication(). It should work at least on Android 4.x.
try {
final Class<?> activityThreadClass =
Class.forName("android.app.ActivityThread");
final Method method = activityThreadClass.getMethod("currentApplication");
return (Application) method.invoke(null, (Object[]) null);
} catch (final ClassNotFoundException e) {
// handle exception
} catch (final NoSuchMethodException e) {
// handle exception
} catch (final IllegalArgumentException e) {
// handle exception
} catch (final IllegalAccessException e) {
// handle exception
} catch (final InvocationTargetException e) {
// handle exception
}
Note that it is possible for this method to return null, e.g. when you call the method outside of the UI thread, or the application is not bound to the thread.
It is still better to use #RohitGhatol's solution if you can change the Application code.
Kotlin way:
Manifest:
<application android:name="MyApplication">
</application>
MyApplication.kt
class MyApplication: Application() {
override fun onCreate() {
super.onCreate()
instance = this
}
companion object {
lateinit var instance: MyApplication
private set
}
}
You can then access the property via MyApplication.instance
It depends on what you are using the context for. I can think of at least one disadvantage to that method:
If you are trying to create an AlertDialog with AlertDialog.Builder, the Application context won't work. I believe you need the context for the current Activity...
Kotlin
open class MyApp : Application() {
override fun onCreate() {
super.onCreate()
mInstance = this
}
companion object {
lateinit var mInstance: MyApp
fun getContext(): Context? {
return mInstance.applicationContext
}
}
}
and get Context like
MyApp.mInstance
or
MyApp.getContext()
If you're open to using RoboGuice, you can have the context injected into any class you want. Here's a small sample of how to do it with RoboGuice 2.0 (beta 4 at time of this writing)
import android.content.Context;
import android.os.Build;
import roboguice.inject.ContextSingleton;
import javax.inject.Inject;
#ContextSingleton
public class DataManager {
#Inject
public DataManager(Context context) {
Properties properties = new Properties();
properties.load(context.getResources().getAssets().open("data.properties"));
} catch (IOException e) {
}
}
}
I've used this at some point:
ActivityThread at = ActivityThread.systemMain();
Context context = at.getSystemContext();
This is a valid context I used at getting system services and worked.
But, I used it only in framework/base modifications and did not try it in Android applications.
A warning that you must know: When registering for broadcast receivers with this context, it will not work and you will get:
java.lang.SecurityException: Given caller package android is not running in process ProcessRecord
If you don't want to modify the manifest file, you can manually store the context in a static variable in your initial activity:
public class App {
private static Context context;
public static void setContext(Context cntxt) {
context = cntxt;
}
public static Context getContext() {
return context;
}
}
And just set the context when your activity (or activities) start:
// MainActivity
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Set Context
App.setContext(getApplicationContext());
// Other stuff
}
Note: Like all other answers, this is a potential memory leak.
in Kotlin, putting Context/App Context in companion object still produce warning Do not place Android context classes in static fields; this is a memory leak (and also breaks Instant Run)
or if you use something like this:
companion object {
lateinit var instance: MyApp
}
It's simply fooling the lint to not discover the memory leak, the App instance still can produce memory leak, since Application class and its descendant is a Context.
Alternatively, you can use functional interface or Functional properties to help you get your app context.
Simply create an object class:
object CoreHelper {
lateinit var contextGetter: () -> Context
}
or you could use it more safely using nullable type:
object CoreHelper {
var contextGetter: (() -> Context)? = null
}
and in your App class add this line:
class MyApp: Application() {
override fun onCreate() {
super.onCreate()
CoreHelper.contextGetter = {
this
}
}
}
and in your manifest declare the app name to . MyApp
<application
android:name=".MyApp"
When you wanna get the context simply call:
CoreHelper.contextGetter()
// or if you use the nullable version
CoreHelper.contextGetter?.invoke()
Hope it will help.
You can use the following:
MainActivity.this.getApplicationContext();
MainActivity.java:
...
public class MainActivity ... {
static MainActivity ma;
...
public void onCreate(Bundle b) {
super...
ma=this;
...
Any other class:
public ...
public ANY_METHOD... {
Context c = MainActivity.ma.getApplicationContext();
According to this source you can obtain your own Context by extending ContextWrapper
public class SomeClass extends ContextWrapper {
public SomeClass(Context base) {
super(base);
}
public void someMethod() {
// notice how I can use "this" for Context
// this works because this class has it's own Context just like an Activity or Service
startActivity(this, SomeRealActivity.class);
//would require context too
File cacheDir = getCacheDir();
}
}
JavaDoc for ContextWrapper
Proxying implementation of Context that simply delegates all of its calls to another Context. Can be subclassed to modify behavior without changing the original Context.
I think you need a body for the getAppContext() method:
public static Context getAppContext()
return MyApplication.context;
If you for some reason want Application context in any class, not just those extending application/activity, maybe for some factory or helper classes. You can add the following singleton to your app.
public class GlobalAppContextSingleton {
private static GlobalAppContextSingleton mInstance;
private Context context;
public static GlobalAppContextSingleton getInstance() {
if (mInstance == null) mInstance = getSync();
return mInstance;
}
private static synchronized GlobalAppContextSingleton getSync() {
if (mInstance == null) mInstance =
new GlobalAppContextSingleton();
return mInstance;
}
public void initialize(Context context) {
this.context = context;
}
public Context getApplicationContext() {
return context;
}
}
then initialize it in your application class's onCreate with
GlobalAppContextSingleton.getInstance().initialize(this);
use it anywhere by calling
GlobalAppContextSingleton.getInstance().getApplicationContext()
I don't recommend this approach to anything but application context however. As it can cause memory leaks.
I use a variation of the Singleton design pattern to help me with this.
import android.app.Activity;
import android.content.Context;
public class ApplicationContextSingleton {
private static Activity gContext;
public static void setContext( Activity activity) {
gContext = activity;
}
public static Activity getActivity() {
return gContext;
}
public static Context getContext() {
return gContext;
}
}
I then call ApplicationContextSingleton.setContext( this ); in my activity.onCreate() and ApplicationContextSingleton.setContext( null ); in onDestroy();
I just released a jQuery-inspired framework for Android called Vapor API that aims to make app development simpler.
The central $ facade class maintains a WeakReference (link to awesome Java blog post about this by Ethan Nicholas) to the current Activity context which you can retrieve by calling:
$.act()
A WeakReference maintains a reference without preventing the garbage collection reclaiming the original object, so you shouldn't have a problem with memory leaks.
The downside of course is that you run the risk that $.act() could return null. I have not come across this scenario yet though, so it's perhaps just a minimal risk, worth mentioning.
You can also set the context manually if you are not using VaporActivity as your Activity class:
$.act(Activity);
Also, much of the Vapor API framework uses this stored context inherently which might mean you needn't store it yourself at all if you decide to use the framework. Check out the site for more information and samples.
I hope that helps :)
Rohit's answer seems correct. However, be aware that AndroidStudio's "Instant Run" depends on not having static Context attributes in your code, as far as I know.
Today the right way to have context is to use dependency injection.
For instance, one can use Hilt to inject context at any place it is needed. Let's say one needs context in some database manager, then this can be resolved in the following way:
Add Hilt in Gradle:
implementation "com.google.dagger:hilt-android:2.35"
kapt "com.google.dagger:hilt-android-compiler:2.35"
Define Application class with #HiltAndroidApp annotation (let it inject the database manager for example):
#HiltAndroidApp
class MyApplication : Application() {
#Inject
lateinit var dbManager: DBManager
override fun onCreate() {
super.onCreate()
dbManager.initDB()
}
}
Define Database manager (let it be #Singleton for example as well):
#Singleton
class DBManager #Inject constructor(
#ApplicationContext private val context: Context
) {
fun initDB() {
// context is avaiable
databaseInit(context)
}
}
And that's it. The DBManager can access context in the right way without memory leaks.
Another alternative to get context without subclassing the Application object and without using hidden classes would be to use a ContentProvider. Once the onCreate method is called, the context should be available. You can do something like this in Kotlin
class ContextContentProvider : ContentProvider() {
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?) = 0
override fun getType(uri: Uri): String? = null
override fun insert(uri: Uri, values: ContentValues?): Uri? = null
override fun onCreate(): Boolean {
applicationContext = context
return true
}
override fun query(
uri: Uri, projection: Array<String>?, selection: String?,
selectionArgs: Array<String>?, sortOrder: String?
): Cursor? = null
override fun update(
uri: Uri, values: ContentValues?, selection: String?,
selectionArgs: Array<String>?
) = 0
companion object {
private var applicationContext: Context? = null
#JvmStatic
fun applicationContext() = applicationContext
}
}
Anywhere you need the context, you can call ContextContentProvider.applicationContext() method
Make sure to use a different authority in the AndroidManifest.xml if you already have another content provider and the content provider is not exported.
<application>
<provider
android:name=".ContextContentProvider"
android:authorities="${applicationId}.ContextContentProvider"
android:enabled="true"
android:exported="false" />
</application>
Related
I have this class acting like a singleton (the instance is not being secured to be recreated again):
class FooInteractorFactory(private val someEvent: SomeEvent) {
companion object {
lateinit var fooFactory: FooInteractorFactory
fun initialize(someEvent: SomeEvent) {
fooFactory = FooInteractorFactory(someEvent)
}
}
fun createSomeObject(): SomeObject {
return SomeObject(someEvent)
}
}
That "singleton" is being initialized inside this class:
class FooImpl : SomeEvent {
init {
FooInteractorFactory.initialize(this)
}
...
}
And FooImpl is being instantiated inside a lifecycle function onCreate() in an Activity:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val foompl = FooImpl()
}
...
}
My question here is FooInteractorFactory, SomeEvent or SomeObject some of them will be leaked or not eligible for Garbage Collection?
As the documentation says,
A class or interface may be unloaded if and only if its defining class loader may be reclaimed by the garbage collector.
this is gonna be eligible, BUT, I'm not sure. I just add to the app LeakCanary, but, the Leak never happened.
I want to be sure based on the experience of each of you.
EDIT
This is how the FooInteractorFactory looks in decompiled java code:
public final class FooInteractorFactory {
private final SomeEvent someEvent;
#NotNull
public static FooInteractorFactory fooFactory;
#NotNull
public final FooInteractorFactory createSomeObject() {
return new SomeObject(this.someEvent);
}
public FooInteractorFactory(#NotNull SomeEvent someEvent) {
this.someEvent = someEvent;
}
public static final class Companion {
#NotNull
public final FooInteractorFactory getFooFactory() {
return FooInteractorFactory.access$getFooFactory$cp();
}
public final void setFooFactory(#NotNull FooInteractorFactory var1) {
FooInteractorFactory.fooFactory = var1;
}
public final void initialize(#NotNull SomeEvent someEvent) {
((FooInteractorFactory.Companion)this).setFooFactory(new FooInteractorFactory(someEvent));
}
}
}
FooInteractorFactory is a static reference of the same class.
AFAIK LeakCanary detects only leaked activities, so it is not designed to detect all memory leaks (finally, how should it now which instance should be garbage collected and which is not?).
Also, what you've attached as a quote is about Class<?>, not about instance. I mean, it says about whole Class definitions, that are being stored in Permanent Generation or Metaspace (depends on Java version).
And about your question: garbage collector usually works in the next way - it starts from references named GC roots, then goes through all the objects via references from these roots, marks them as "alive", and reclaims memory from all the objects that were not marked as alive (I mean, that are not available through GC-roots). References known as GC-roots are :
Local variables
static variables
Active Threads
JNI references
I doubt any of Class objects that you have mentioned are going to be unloaded from JVM in case you haven't define your own ClassLoader or messed with their lifecycle.
Talking about instances:
I have this class acting like a singleton (the instance is not being secured to be recreated again)
If comanion's object fooFactory reference referred object A and then was reassigned with object B, then if A is not referenced with any other GC-roots or intermediate references that are available through GC-roots, than in few GC cycles this intance will be garbage collected.
The same goes for all the other instances.
I create a unit test for my Presenter. My Presenter implements Listener callback if successfully load data from API (use Interactor):
PresenterTest.java
public class MainContactPresenterTest {
#Mock LoadContactInteractor loadContactInteractor;
#Mock ApiService apiService;
#Mock LoadContactView loadContactView;
#Mock ContactRepository contactRepository;
#Mock LoadContactInteractor.OnLoadDataFinishedListener listener;
#InjectMocks MainContactPresenterImpl presenter;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void getContactLists() {
// given
// when
presenter.fetchRemoteContacts();
// then
Mockito.verify(loadContactInteractor).onLoadData(listener);
}
}
Here is my Presenter:
public class MainContactPresenterImpl implements MainContactPresenter,
LoadContactInteractor.OnLoadDataFinishedListener {
private LoadContactView loadContactView;
private LoadContactInteractor loadContactInteractor;
private ContactRepository contactRepository;
#Inject
public MainContactPresenterImpl(LoadContactInteractor loadContactInteractor,
#NonNull LoadContactView loadContactView,
ContactRepository contactRepository) {
this.loadContactView = loadContactView;
this.loadContactInteractor = loadContactInteractor;
this.contactRepository = contactRepository;
}
#Override
public void onSuccessLoad(List<Contact> contacts) {
loadContactView.saveDataToLocalStorage(contacts);
}
#Override
public void onErrorLoad() {
loadContactView.dismissProgress();
loadContactView.showErrorMessage();
}
#Override
public void preCheckCacheData() {
if (contactRepository.getContactCount() == 0) {
// Load contacts from Server
fetchRemoteContacts();
} else {
fetchLocalContacts();
}
}
#Override
public void fetchRemoteContacts() {
loadContactView.showProgress();
loadContactInteractor.onLoadData(this);
}
}
But when I ran test, I got the mocking parameter in verify not match.
I got my presenter that have to be an argument. Not the listener.
Argument(s) are different! Wanted:
loadContactInteractor.onLoadData(
listener
);
Actual invocation has different arguments:
loadContactInteractor.onLoadData(
fanjavaid.gojek.com.contacts.presenter.MainContactPresenterImpl#1757cd72
);
How to handle that? Thank you
You are creating a mock...
#Mock LoadContactInteractor.OnLoadDataFinishedListener listener;
...and then you don't use it ever again and act suprised when verify tells you, that it wasn't actually used. Why? Of course it wasn't used, since you never use it anywhere, so how should your classes know to use that mock object?
Your MainContactPresenterImpl does not use an OnLoadDataFinishedListener as an external dependency (then your could perhaps inject it via #InjectMocks), it is itself such a listener and thus mocking another listener makes no sense here.
In other words, MainContactPresenterImpl has no OnLoadDataFinishedListener field, so Mockito is of course not capable of injecting something in this non-existing field. For something like this to work, you would need to add such a field and then use the content of that field when calling your onLoadData method.
The only invocation of your method is here...
loadContactInteractor.onLoadData(this);
And what is this in that context? It's the MainContactPresenterImpl object that contains the method, in other words, your presenter.
So, what will work is...
Mockito.verify(loadContactInteractor).onLoadData(presenter);
I am using ViewModel, introduced in IO/17.
I am using following guidelines provided on android developers page.
https://developer.android.com/topic/libraries/architecture/viewmodel.html
Following is their sample code.
public class MyViewModel extends ViewModel {
private MutableLiveData<List<User>> users;
public LiveData<List<User>> getUsers() {
if (users == null) {
users = new MutableLiveData<List<Users>>();
loadUsers();
}
return users;
}
private void loadUsers() {
// do async operation to fetch users
}
}
I wish to perform Volley request in the 'loadUsers()' method. But I cannot do it as it needs a 'context' as follows
Volley.newRequestQueue(context).add(jsonObjectRequest);
So my question is,
Is it recommended(or possible) to perform network operations inside a ViewModel??
If yes(if possible), how to do it?
You could use the AndroidViewModel class instead of ViewModel. AndroidViewModel holds a reference to the application context.
https://youtu.be/5qlIPTDE274
Consider Dagger, that way you don't have to worry, about providing context for Volley from your ViewModel.
AndroidViewModel is subclass of ViewModel. The Difference between them is we can pass Application Context which can be used whenever Application Context is required for example to instantiate Database in Repository.
AndroidViewModel is a Application context aware ViewModel.You must use AndroidViewModel for Application Context.
public class MyViewModel extends AndroidViewModel {
private MutableLiveData<List<User>> users;
private Application application;
public MyViewModel(#NonNull Application application) {
this.application=application;
super(application);
}
public LiveData<List<User>> getUsers() {
if (users == null) {
users = new MutableLiveData<List<Users>>();
loadUsers();
}
return users;
}
private void loadUsers() {
// Pass Context to Repository
}}
You should never store a reference of activity or a view that references a activity in the ViewModel.Because ViewModel is designed to outlive a activity and it will cause Memory Leak.
Is it recommended(or possible) to perform network operations inside a
ViewModel??
No, you should not perform Networking Operations inside a ViewModel.
If yes(if possible), how to do it?
Get Application Context by using AndroidModelView and pass it to Repository,
as recommended by Android Team.
Alright, I'm having an issue trying to mix frameworks.
So, I have a #SharedPref annotated class that should generate a Shared Preferences manager from Android Annotations. The class looks a bit something like this:
DownloadPrefs.java
#SharedPref(value= SharedPref.Scope.UNIQUE)
public interface DownloadPrefs {
#DefaultBoolean(false)
boolean hasEnabledDownload();
#DefaultBoolean(false)
boolean showedDownloadDialog();
#DefaultLong(0)
long downloadRefreshedOn();
}
Now, I'd like to inject the resulting class (which will be DownloadPrefs_) into a Fragment to make use of it. The fragment has had working injection before adding the new module, so I'm only going to write here what I added:
Fragment.java
#Inject DownloadPrefs_ downloadPrefs;
Now, since the actual DownloadPrefs_ class is generated at runtime, it would make the most sense to create an #Provides annotation for it, since I can't mark a constructor as injected. Nor does the DownloadPrefs_ have a no-arg constructor. The module I'm using then receives the new #Provides:
DownloaderModule.java
#Provides //#Singleton // Does not work with/out #Singleton
DownloadPrefs_ provideDownloadPrefs() {
return new DownloadPrefs_(MinimalBible.getApplication());
}
To be technical about it, the DownloadPrefs_ constructor that gets generated by Android Annotations expects a Context passed to it, I would have guessed that the Application context would be suitable. Otherwise, I'm not sure how I could possibly get access to the Activity context. Or whether that would actually break the ObjectGraph.
However, when I go to run the actual injection, I get the following message:
Caused by: java.lang.IllegalStateException: Errors creating object graph:
org.bspeice.minimalbible.activities.downloader.DownloadPrefs_ has no injectable members. Do you want to add an injectable constructor? required by class org.bspeice.minimalbible.activities.downloader.BookListFragment
Any clue on what's going on? It doesn't seem like the questions asking about "no injectable members" on other SO questions answered my case. I had a working app before adding the code above.
UPDATE: After doing some double-checking, I came across the following weird behavior. If I copy out the pre-built Android Annotations class, rename it, and inject that, everything works. Additionally, I can verify that the original built Android Annotations class (the DownloadPrefs_.java) does in fact exist in the .dex, so Dagger should have no reason to not be able to find it. Everything is doing a debug build, so I can't imagine ProGuard is messing anything up.
At this point, I'm going to create a minimal project to demonstrate the error, and file an issue with Dagger. In the mean time, just need to rewrite the Prefs class until I can get this sorted out.
UPDATE 5/12/2014
Here are the modules responsible for injection:
MinimalBibleModules.java
#Module(
injects = {
MinimalBible.class
},
includes = {
ActivityModules.class
}
)
public class MinimalBibleModules {
}
ActivityModules.java
#Module(
includes = {
ActivityDownloaderModule.class
}
)
public class ActivityModules {
}
ActivityDownloaderModule.java
#Module(
injects = {
BookListFragment.class,
DownloadManager.class,
BookRefreshTask.class
}
)
public class ActivityDownloaderModule {
#Provides #Singleton
DownloadManager provideDownloadManager() {
return new DownloadManager();
}
#Provides
EventBus provideBus() {
return new EventBus();
}
#Provides //#Singleton
DownloadPrefs_ provideDownloadPrefs() {
return new DownloadPrefs_(MinimalBible.getApplication());
}
}
Also, how the graph gets created:
MinimalBible.java
public class MinimalBible extends Application {
private ObjectGraph graph;
private static MinimalBible instance;
public MinimalBible() {
instance = this;
}
#Override
public void onCreate() {
graph = ObjectGraph.create(new MinimalBibleModules());
graph.inject(this);
}
There are two parts here. First, how you get access to the Context. You can do static things as you are, though that's not advisable. Generally, you should configure your graph with a stateful module that carries the context, like this:
#Module
class ApplicationModule {
private final Application application;
public ApplicationModule(Application app) {
this.application = app;
}
// you can mark this singleton, but it's minor overhead
// and the fact that you have a single instance stored
// means it's semantically equivalent. But for clarity
// it's sometimes good to make the point.
#Provides
#Singleton
Application application() {
return application;
}
// optionally: bind it as a Context with a qualifier.
// note: never bind Context without a qualifier annotation
// as Activity and Application are both Context subtypes.
#Provides
#Singleton
#PerApplication
Context appContext(Application app) {
// Doing this instead of returning this.application is
// semantically equivalent but links #PerApplication Context
// to Application, so in graph analysis and error reporting
// the link is clearer. That's a personal choice.
return app;
}
}
At any rate, you then when you create the graph:
Application appInstance = ...;
ObjectGraph appGraph = ObjectGraph.create(
MyAppModule.class,
new ApplicationModule(appInstance));
The Application is then seeded into the graph and can be depended-upon by other types that declare it as a dependency.
Does anyone know how can you get the context of the Test project in Android junit test case (extends AndroidTestCase).
Note: The test is NOT instrumentation test.
Note 2: I need the context of the test project, not the context of the actual application that is tested.
I need this to load some files from assets from the test project.
There's new approach with Android Testing Support Library (currently androidx.test:runner:1.1.1). Kotlin updated example:
class ExampleInstrumentedTest {
lateinit var instrumentationContext: Context
#Before
fun setup() {
instrumentationContext = InstrumentationRegistry.getInstrumentation().context
}
#Test
fun someTest() {
TODO()
}
}
If you want also app context run:
InstrumentationRegistry.getInstrumentation().targetContext
Full running example: https://github.com/fada21/AndroidTestContextExample
Look here: What's the difference between getTargetContext() and getContext (on InstrumentationRegistry)?
After some research the only working solution seems to be the one yorkw pointed out already. You'd have to extend InstrumentationTestCase and then you can access your test application's context using getInstrumentation().getContext() - here is a brief code snippet using the above suggestions:
public class PrintoutPullParserTest extends InstrumentationTestCase {
public void testParsing() throws Exception {
PrintoutPullParser parser = new PrintoutPullParser();
parser.parse(getInstrumentation().getContext().getResources().getXml(R.xml.printer_configuration));
}
}
As you can read in the AndroidTestCase source code, the getTestContext() method is hidden.
/**
* #hide
*/
public Context getTestContext() {
return mTestContext;
}
You can bypass the #hide annotation using reflection.
Just add the following method in your AndroidTestCase :
/**
* #return The {#link Context} of the test project.
*/
private Context getTestContext()
{
try
{
Method getTestContext = ServiceTestCase.class.getMethod("getTestContext");
return (Context) getTestContext.invoke(this);
}
catch (final Exception exception)
{
exception.printStackTrace();
return null;
}
}
Then call getTestContext() any time you want. :)
If you want to get the context with Kotlin and Mockito, you can do it in the following way:
val context = mock(Context::class.java)
import androidx.test.core.app.ApplicationProvider;
private Context context = ApplicationProvider.getApplicationContext();
#RunWith(AndroidJUnit4.class) let you use Android Context
/**
* Instrumented test, which will execute on an Android device.
*
* #see Testing documentation
*/
#RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
#Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.android.systemui", appContext.getPackageName());
}
}
You can even run it on main thread using runOnMainSync. Here is the complete solution:
#RunWith(AndroidJUnit4::class)
class AwesomeViewModelTest {
#Test
fun testHandler() {
getInstrumentation().runOnMainSync(Runnable {
val context = InstrumentationRegistry.getInstrumentation().targetContext
// Here you can call methods which have Handler
})
}
}
Update: AndroidTestCase This class was deprecated in API level 24.
Use InstrumentationRegistry instead. New tests should be written using the Android Testing Support Library. Link to announcement
You should extend from AndroidTestCase instead of TestCase.
AndroidTestCase Class Overview
Extend this if you need to access Resources or other things that depend on Activity Context.
AndroidTestCase - Android Developers
This is to correct way to get the Context. Other methods are already deprecated
import androidx.test.platform.app.InstrumentationRegistry
InstrumentationRegistry.getInstrumentation().context
The other answers are outdated. Right now every time that you extend AndroidTestCase, there is mContext Context object that you can use.
For those encountering these problems while creating automated tests, you've gotta do this :
Context instrumentationContext;
#Before
public void method() {
instrumentationContext = InstrumentationRegistry.getInstrumentation().getContext();
MultiDex.install(instrumentationContext);
}
Add Mocito Library
testImplementation 'junit:junit:4.13.2'
testImplementation 'androidx.test:core:1.4.0'
testImplementation 'org.mockito:mockito-core:3.10.0'
Add Annoatation call #Mock where ever need for example for Context
#RunWith(MockitoJUnitRunner::class)
class EmailValidatorTest {
#Mock
private lateinit var context: Context
lateinit var utils:Utils
#Before
fun launch()
{
utils=Utils(context)
}
#Test
fun emailValidator_NullEmail_ReturnsFalse() {
assertFalse(utils.isValidEmail(null))
}
}
For Kotlin unit test with #RunWith(AndroidJUnit4::class)
Add this dependency for kotlin test
implementation 'androidx.test:core-ktx:1.5.0'
In the test class access context using the below snippet.
private val context = ApplicationProvider.getApplicationContext<Context>()