cannot instantiate viewModelProviders in activity
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
public class MainActivity extends AppCompatActivity {
private NoteViewModel noteViewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
noteViewModel = ViewModelProviders.of(this).get(NoteViewModel.class);
noteViewModel.getAllNotes().observe(this, new Observer <List<Note>> () {
#Override
public void onChanged(#Nullable List <Note> notes) {
//update RecyclerView
Toast.makeText(MainActivity.this, "onChanged", Toast.LENGTH_SHORT).show();
}
});
}
}
As you are using Android x make sure you implement those dependencies in your build.gradle file
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
annotationProcessor "androidx.lifecycle:compiler:$lifecycle_version"
Then make sure you indicate those properties in your gradle.properties
android.useAndroidX=true
android.enableJetifier=true
Finally you should check if you import AppCompatActivity from Androidx not support
import androidx.appcompat.app.AppCompatActivity;
Besides Amine's answer i think it's worth checking if you are using the proper viewmodel provider.
ViewModelProvider does not have .of()... However, ViewModelProviders notice the s in the end has the method .of().
Related
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'm following the dev guide here:
https://developer.android.com/guide/components/activities/testing
and have a test class like:
#RunWith(AndroidJUnit4::class)
class MyTestSuite {
#get:Rule var activityScenarioRule = activityScenarioRule<MyActivity>()
#Test fun testEvent() {
val scenario = activityScenarioRule.scenario
}
}
the method activityScenarioRule<T>() is not defined. What dependency do I need? Also, what is the best way to determine which dependencies to add when reading these docs?
The activityScenarioRule<T>() method is part of the androidx.test.ext:junit-ktx:1.1.0 dependency.
Usually, this would be listed under the List of AndroidX Test dependencies, but it appears it isn't up to date with the junit-ktx or core-ktx modules as of yet, despite it being explicitly mentioned as part of the Version 1.1.0-beta01 release notes
If you are not using the ktx dependency, e.g. androidx.test.ext:junit:1.1.2 you can do it like this:
#get:Rule
var activityScenarioRule = ActivityScenarioRule(MyActivity::class.java)
I had a similar problem.
Changing dependency from testImplementation 'androidx.test.ext:junit:1.1.3'
to androidTestImplementation 'androidx.test.ext:junit:1.1.3' worked for me.
My example of usage ActivityScenarioRule<> for Java:
public class AdMobContainerImplTest {
private static final String TAG = AdMobContainerImplTest.class.getSimpleName();
#Rule
public ActivityScenarioRule<ENDetailsActivity> mActivityRule = new ActivityScenarioRule<>(
ENDetailsActivity.class);
#Test
public void testAdVisibility() {
mActivityRule.getScenario().onActivity(activity -> {
AdView ad = activity.findViewById(R.id.ad_banner);
ad.setAdListener(new AdListener() {
#Override
public void onAdLoaded() {
super.onAdLoaded();
Log.i(TAG, "ad loaded");
Assert.assertNotNull(ad);
onView(withId(R.id.ad_banner)).check(matches(isDisplayed()));
}
});
});
}
}
I have this:
import android.arch.*;
public class ScrollingActivity extends AppCompatActivity {
private PeriodicWorkRequest notificationWorkSingle;
private WorkManager mWorkManager;
}
I love how not a single tutorial shows us which class to import
How to import PeriodicWorkRequest and WorkManager?
Of course:
import androidx.work.WorkManager;
import androidx.work.PeriodicWorkRequest;
and use this in build.gradle
dependencies {
implementation "android.arch.work:work-runtime:1.0.0-beta02"
}
and
dependencies {
classpath "android.arch.work:work-runtime:1.0.0-beta02"
}
A small addition to the answer by Alexander Mills:
Here's the link to the official docs on how to add Architecture Components to your project ->
Adding Components to your Project
I am a bit new in testing, so bear with me.
I would like to test the behavior of onDismiss() method of mine. I would like to make sure that onDismiss() calls the showDialog() method for sure. In order to do this, I would like to verify is the mock in showDialog() being called or not.
I am getting an error message, saying there is no interaction with that mock. If I run it with deBug mode, I see we step on the loadingDialog.show() line, still I am getting this error.
Questions:
I would like to know, how can I test a subMethod call in this case?
Why is this happening?
(showDialog() is already covered by separate tests)
test:
sut.onDismiss(mockDialog)
verify(mockLoadingDialog, times(1)).show();
code:
public void onDismiss(DialogInterface dialog) {
showDialog();
}
public synchronized void showDialog() {
loadingDialog.show();
}
Error message: Actually, there were zero interactions with this mock.
package junit;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
#RunWith(MockitoJUnitRunner.class)
public class BasicTest {
#InjectMocks
private Basic basic;
#Mock
private LoadingDialog mockLoadingDialog;
#Mock
private DialogInterface dialog;
#Before
public void setUp() throws Exception {
}
#After
public void tearDown() throws Exception {
}
#Test
public void testOnDismiss() {
basic.onDismiss(dialog);
verify(mockLoadingDialog, times(1)).show();
}
}
Hope this helps!
Using #InjectMocks ensures that the mocks are injected wherever necessary and you do not have to init mocks in setup.
Im trying to do a very simple dependency injection in a Android app. I am using dagger 2 as a DI tool.
The issue is no injection is occuring:
here is my code:
//behold Motor.java in all its awe.
public class Motor {
private int rpm;
public Motor(){
this.rpm = 10; //default will be 10
}
public int getRpm(){
return rpm;
}
public void accelerate(int value){
rpm = rpm + value;
}
public void brake(){
rpm = 0;
}
}
and here is the Vehicle.java which utilities the motor class:
import javax.inject.Inject;
public class Vehicle {
private Motor motor;
#Inject
public Vehicle(Motor motor){
this.motor = motor;
}
public void increaseSpeed(int value){
motor.accelerate(value);
}
public void stop(){
motor.brake();
}
public int getSpeed(){
return motor.getRpm();
}
}
I then created a VehicleModule.java class to define my provider:
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
#Module
public class VehicleModule {
#Provides
#Singleton
Motor provideMotor(){
return new Motor();
}
#Provides #Singleton
Vehicle provideVehicle(){
return new Vehicle(new Motor());
}
}
I then i have a interface component annotated, defined like this:
import javax.inject.Singleton;
import Modules.VehicleModule;
import dagger.Component;
#Singleton
#Component(modules = {VehicleModule.class})
public interface VehicleComponent {
Vehicle provideVehicle();
}
and here is my Android mainactivity class that should be injected but its not, can anyone help:
import javax.inject.Inject;
public class MainActivity extends ActionBarActivity {
#Inject
Vehicle vehicle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toast.makeText(this, String.valueOf(vehicle.getSpeed()), Toast.LENGTH_SHORT).show();
}
}
im getting a null pointer exception on vehicle:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int com.example.uen229.myapplication.Vehicle.getSpeed()' on a null object reference
by the way my gradle dependencies look like this:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.2.0'
compile 'com.google.dagger:dagger:2.0'
}
here is my Android mainactivity class that should be injected but its not
You're expecting magical things happen when you annotate something with #Inject. While magical things will happen, it's not that magical. You will need to do that yourself, by instantiating the component implementations that Dagger generated.
You can do this in a couple of ways, I will describe two.
First, in your MainActivity's onCreate:
private Vehicle vehicle; // Note, no #Inject annotation
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
VehicleComponent vehicleComponent = DaggerVehicleComponent.create();
this.vehicle = vehicleComponent.provideVehicle();
Toast.makeText(this, String.valueOf(vehicle.getSpeed()), Toast.LENGTH_SHORT).show();
}
In this case, you create an instance of VehicleComponent, implemented by Dagger, and fetch the Vehicle instance from it. The vehicle field is not annotated by #Inject. This has the advantage that the field can be private, which is a good thing to want.
Secondly, if you do want Dagger to inject your fields, you need to add an inject method to your VehicleComponent:
#Singleton
#Component(modules = {VehicleModule.class})
public interface VehicleComponent {
Vehicle provideVehicle();
void inject(MainActivity mainActivity);
}
In your MainActivity class, you call inject(this), which will fill the vehicle field:
#Inject
Vehicle vehicle; // Note, package-local
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
VehicleComponent vehicleComponent = DaggerVehicleComponent.create();
vehicleComponent.inject(this);
Toast.makeText(this, String.valueOf(vehicle.getSpeed()), Toast.LENGTH_SHORT).show();
}
This brings a bit of extra configuration, but is sometimes necessary.
I like the first method however.
As a final comment, let's have a look at your VehicleModule, and really use the power of Dagger.
Instead of using the module to create the instances yourself, you can make Dagger to that for you. You've already annotated the Vehicle constructor with #Inject, so Dagger will know to use this constructor. However, it needs an instance of Motor, which it doesn't know of. If you add an #Inject annotation to the constructor of Motor as well, and annotate the Motor class with #Singleton, you can get rid of the VehicleModule altogether!
For example:
#Singleton
public class Motor {
private int rpm;
#Inject // Just an annotation to let Dagger know how to retrieve an instance of Motor.
public Motor(){
this.rpm = 10; //default will be 10
}
public int getRpm(){
return rpm;
}
public void accelerate(int value){
rpm = rpm + value;
}
public void brake(){
rpm = 0;
}
}
Your Vehicle class:
#Singleton
public class Vehicle {
private Motor motor;
#Inject
public Vehicle(Motor motor){
this.motor = motor;
}
public void increaseSpeed(int value){
motor.accelerate(value);
}
public void stop(){
motor.brake();
}
public int getSpeed(){
return motor.getRpm();
}
}
You can now safely delete the VehicleModule class, and remove the reference to it in your VehicleComponent.
you are missing the following steps
you have create the module like this in application class
public class D2EApplication extends Applicaiton {
public static D2EComponent component(Context context) {
return ((D2EBaseApplication) context.getApplicationContext()).component;
}
public final static class DaggerComponentInitializer {
public static D2EComponent init(D2EBaseApplication app) {
return DaggerD2EComponent.builder()
.systemServicesModule(new VehicleModule(app))
.build();
}
}
}
and inject it to the activity
D2EApplication.component(this).inject(this);