Please check below my Module class in which I have defined my object which need to be inject using Hilt
NVModule.kt
#Module
#InstallIn(SingletonComponent::class)
class NVModule {
#Provides
#Named("ProfileHelper")
fun abprovideProfileHelper(): ProfileHelper {
return ProfileHelper(AppController.getInstance())
}
}
And now please check my Interface by which i have used the EntryPoint to access my dependency injection outside the Activity/Fragment like Helper class.
#EntryPoint
#InstallIn(SingletonComponent.class)
public interface CommonHiltInterface {
#Named("ProfileHelper")
public ProfileHelper provideProfileHelper();
}
}
Now please check the my Activity class on which i have used the dependency injection like below and it is working fine here. Means getting dependency injection properly
public class HomeActivity extends BaseActivity{
private ActivityHomescreenBinding
activityHomescreenBinding;
private Activity context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = this;
activityHomescreenBinding =
DataBindingUtil.inflate(getLayoutInflater(),
R.layout.activity_homescreen, null, false);
setContentView(activityHomescreenBinding.getRoot());
CommonHiltInterface commonHiltInterface = EntryPointAccessors.fromApplication(context, CommonHiltInterface.class);
commonHiltInterface.provideProfileHelper().setData();
}
}
But in case of the Test cases , dependency injection getting NullPointerException . I am using the Robolectric for the test cases. Please check my below lines of code for the RobolectricTest case.
#HiltAndroidTest
#RunWith(RobolectricTestRunner.class)
#Config(application = HiltTestApplication.class,
sdk = Build.VERSION_CODES.N, manifest = Config.NONE)
public class HomeActivityTest {
#Rule
public HiltAndroidRule hiltRule = new
HiltAndroidRule(this);
#Before
public void setUp() throws Exception {
shadowOf(Looper.getMainLooper()).idle();
hiltRule.inject();
activity =
Robolectric.buildActivity(HomeActivity.class).
create().resume().get();
}
}
Note :- 1). I have also use #HiltAndroidApp() for application class.and using 2.36 version for hilt dependency
2). My dependency injection working fine for the Java classes like Activity/Fagment and Helper classes , But not working in test cases.
Please check my dependency for Hilt are as follow
testImplementation 'com.google.dagger:hilt-android-testing:2.36'
kaptTest 'com.google.dagger:hilt-android-compiler:2.36'
testAnnotationProcessor 'com.google.dagger:hilt-android-compiler:2.36'
androidTestImplementation 'com.google.dagger:hilt-android-testing:2.36'
kaptAndroidTest 'com.google.dagger:hilt-android-compiler:2.36'
Application runs successfully but in case of Test case I am getting the null pointer exception below lines of code in Activity (HomeActivity).
CommonHiltInterface commonHiltInterface = EntryPointAccessors.fromApplication(context, CommonHiltInterface.class);
commonHiltInterface.provideProfileHelper().setData();
I am running a unit test with
#RunWith(MockitoJUnitRunner.class)
I have used firebase Analytics to log events
MyApplication.getAnalytics().getInstance(appContext).logEvent(eventType, bundle)
and this in my Application class
public static FirebaseAnalytics getAnalytics() {
return FirebaseAnalytics.getInstance(appContext);
}
Now while running tests, I am getting NullPointerException. What will be the right way to initialize Analytics for my unit tests or just ignore them.
I am not getting the context in case I try to initialize it in my setup method of tests.
You can create a mock application class that extends your application class and then overrides getAnalytics with a stubbed value or mock object. Also you should make your getAnalytics method non-static as it's easier for testing and you can pass the reference via dependency injection or you can use a static reference to the application class (but that isn't very testable so I would choose the first option)
public class MockApplication extends MyApplication {
public FirebaseAnalytics getAnalytics() {
return mock(FirebaseAnalytics.class)
}
}
Then you can use the #Config annotation to configure your test runner like this
#RunWith(RobolectricTestRunner.class)
#Config(constants = BuildConfig.class, sdk = Build.VERSION_CODES.M, application = MockApplication.class)
Check this link out https://github.com/robolectric/robolectric/wiki/Using-PowerMock
Refactor yours like this:
#RunWith(RobolectricTestRunner.class)
#Config(constants = BuildConfig.class)
#PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*" })
#PrepareForTest(FirebaseAnalytics.class)
public class TestClass {
#Rule
public PowerMockRule rule = new PowerMockRule();
private FirebaseAnalytics firebase;
#Test
public void testMocking() {
firebase = PowerMockito.mock(FirebaseAnalytics.class);
Context context = PowerMockito.mock(Context.class);
PowerMockito.mockStatic(FirebaseAnalytics.class);
Mockito.when(FirebaseAnalytics.getInstance(context)).thenReturn(firebase);
}
}
The DaggerMock library, is used to override dagger modules with fake implementation. Lets take a look at one robolectric topic that is confusing me:
#RunWith(RobolectricGradleTestRunner.class)
#Config(constants = BuildConfig.class, sdk = 21)
public class MainActivityTest {
#Rule public final DaggerMockRule<MyComponent> mockitoRule = new DaggerMockRule<>(MyComponent.class, new MyModule())
.set(new DaggerMockRule.ComponentSetter<MyComponent>() {
#Override public void setComponent(MyComponent component) {
((App) RuntimeEnvironment.application).setComponent(component);
}
});
#Mock RestService restService;
#Mock MyPrinter myPrinter;
#Test
public void testCreateActivity() {
when(restService.doSomething()).thenReturn("abc");
Robolectric.setupActivity(MainActivity.class);
verify(myPrinter).print("ABC");
}
}
So i want to know, with this Rule what exactly is happening ? I can see that RestService was being provided by MyModule but is now being replaced with a mock. But in the examples i don't see a #Inject anywhere so i'm confused how the module was even used in the first place to provide any dependencies ?
I am the author of DaggerMock, thanks for trying it!
The implementation is a bit complicated, the rule create a dynamic subclass of the module (using mockito) and override the provides methods. The rule scans the test fields so it return a field when the module has a method that returns the same type.
The final result is very similar to Mockito InjectMocks annotation. You can take a look at the implementation on github, the core class that override the module is this: https://github.com/fabioCollini/DaggerMock/blob/master/lib/src/main/java/it/cosenonjaviste/daggermock/MockOverrider.java
I release this lib just a week ago, any feedback is welcome!
I've just started unit testing on Android with Mockito - how do you get the class that you are testing on to use the mocked class/object instead of the regular class/object?
You can use #InjectMocks for the class you writing the test.
#InjectMocks
private EmployManager manager;
Then you can use #Mock for the class you are mocking. This will be the dependency class.
#Mock
private EmployService service;
Then write a setup method to make things available for your tests.
#Before
public void setup() throws Exception {
manager = new EmployManager();
service = mock(EmployService.class);
manager.setEmployService(service);
MockitoAnnotations.initMocks(this);
}
Then write your test.
#Test
public void testSaveEmploy() throws Exception {
Employ employ = new Employ("u1");
manager.saveEmploy(employ);
// Verify if saveEmploy was invoked on service with given 'Employ'
// object.
verify(service).saveEmploy(employ);
// Verify with Argument Matcher
verify(service).saveEmploy(Mockito.any(Employ.class));
}
By injecting the dependency:
public class ClassUnderTest
private Dependency dependency;
public ClassUnderTest(Dependency dependency) {
this.dependency = dependency;
}
// ...
}
...
Dependency mockDependency = mock(Dependency.class);
ClassUnderTest c = new ClassUnderTest(mockDependency);
You can also use a setter to inject the dependency, or even inject private fields directly using the #Mock and #InjectMocks annotations (read the javadoc for a detailed explanation of how they work).
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>