sockeqwe / mosby

A Model-View-Presenter / Model-View-Intent library for modern Android apps
http://hannesdorfmann.com/mosby/
Apache License 2.0
5.49k stars 841 forks source link

Dagger2 - injecting presenter gives Caused by: java.lang.NullPointerException: Presenter returned from createPresenter() is null. Activity is ... #298

Open j2emanue opened 6 years ago

j2emanue commented 6 years ago

i was successfully using mosby2 for a long time now and changed to mosby3. at runtime the presenter cannot be created. Tested on Oreo api 26 emulator xxhdpi.

Here are the dependencies:

implementation 'com.hannesdorfmann.mosby3:mvp:3.1.0' // Plain MVP implementation 'com.hannesdorfmann.mosby3:viewstate:3.1.0' // MVP + ViewState support

If i do the following which is creating the presenter without dependency injection there is no issue: @NonNull @Override public WelcomePresenter createPresenter() { return new WelcomePresenter(); }

but the following gives a NPE when using dagger2 in android:

public class AuthenticationActivity extends MyappBaseMvpActivity<AuthenticationView, AuthenticationPresenter> implements AuthenticationView {

    @Inject
    AuthenticationPresenter presenter; //confirmed this value is not null

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ((MyappApplication) getApplicationContext()).getAppComponent().inject(this); //injecting presenter which works in Mosby2
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_authentication);
        ButterKnife.bind(this);
        presenter.loadScreen(); 
        //blah blah
    }

@NonNull
    @Override
    public AuthenticationPresenter createPresenter() {
        return presenter; //confirmed through debugger this value is NOT null
    }
  }

Here is what i have tried: moving the " ((MyAppApplication) getApplicationContext()).getAppComponent().inject(this);" call after the super call and even after setnContentView. Same issues.

Here is the exact error i recieve :

FATAL EXCEPTION: main Process: com.mobile.myapp.labs, PID: 2680 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mobile.myapp.labs/com.mobile.myapp.ui.login.activities.AuthenticationActivity}: java.lang.NullPointerException: Presenter returned from createPresenter() is null. Activity is com.mobile.myapp.ui.login.activities.AuthenticationActivity@8ba807c at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2817) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892) at android.app.ActivityThread.-wrap11(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593) at android.os.Handler.dispatchMessage(Handler.java:105) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6541) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767) Caused by: java.lang.NullPointerException: Presenter returned from createPresenter() is null. Activity is com.mobile.myapp.ui.login.activities.AuthenticationActivity@8ba807c at com.hannesdorfmann.mosby3.mvp.delegate.ActivityMvpDelegateImpl.createViewIdAndCreatePresenter(ActivityMvpDelegateImpl.java:92) at com.hannesdorfmann.mosby3.mvp.delegate.ActivityMvpDelegateImpl.onCreate(ActivityMvpDelegateImpl.java:142) at com.hannesdorfmann.mosby3.mvp.MvpActivity.onCreate(MvpActivity.java:42) at com.mobile.myapp.ui.base.MyappBaseMvpActivity.onCreate(MyappBaseMvpActivity.java:88) at com.mobile.myapp.ui.login.activities.AuthenticationActivity.onCreate(AuthenticationActivity.java:56) at android.app.Activity.performCreate(Activity.java:6975) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)  at android.app.ActivityThread.-wrap11(Unknown Source:0)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)  at android.os.Handler.dispatchMessage(Handler.java:105)  at android.os.Looper.loop(Looper.java:164)  at android.app.ActivityThread.main(ActivityThread.java:6541)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)  12-22 08:58:10.863 1811-1823/system_process E/memtrack: Couldn't load memtrack module

sockeqwe commented 6 years ago

Hm, seems you have implemented it correctly. You have to do the dependency injection in onCreate() BEFORE calling super.onCreate() which you did.

I think the problem is the following: If you inject into your own presenter variable (I explicitly say own variable, because Mosby internally already has a presenter variable too), you also have to override getPresenter() and setPresenter() of MvpActivity(). Please try to add this two methods.

j2emanue notifications@github.com schrieb am Fr., 22. Dez. 2017, 10:13:

i was successfully using mosby2 for a long time now and changed to mosby3. at runtime the presenter cannot be created. Tested on Oreo api 26 emulator xxhdpi.

Here are the dependencies:

implementation 'com.hannesdorfmann.mosby3:mvp:3.1.0' // Plain MVP implementation 'com.hannesdorfmann.mosby3:viewstate:3.1.0' // MVP + ViewState support

If i do the following which is creating the presenter without dependency injection there is no issue: @nonnull https://github.com/nonnull @override https://github.com/override public WelcomePresenter createPresenter() { return new WelcomePresenter(); }

but the following gives a NPE when using dagger2 in android:

public class AuthenticationActivity extends MyappBaseMvpActivity<AuthenticationView, AuthenticationPresenter> implements AuthenticationView {

@Inject
AuthenticationPresenter presenter; //confirmed this value is not null

@Override
protected void onCreate(Bundle savedInstanceState) {
    ((MyappApplication) getApplicationContext()).getAppComponent().inject(this); //injecting presenter which works in Mosby2
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_authentication);
    ButterKnife.bind(this);
    presenter.loadScreen();
    //blah blah
}

@NonNull @Override public AuthenticationPresenter createPresenter() { return presenter; //confirmed through debugger this value is NOT null } }

Here is what i have tried: moving the " ((MyAppApplication) getApplicationContext()).getAppComponent().inject(this);" call after the super call and even after setnContentView. Same issues.

Here is the exact error i recieve :

FATAL EXCEPTION: main Process: com.mobile.myapp.labs, PID: 2680 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mobile.myapp.labs/com.mobile.myapp.ui.login.activities.AuthenticationActivity}: java.lang.NullPointerException: Presenter returned from createPresenter() is null. Activity is com.mobile.myapp.ui.login.activities.AuthenticationActivity@8ba807c at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2817) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892) at android.app.ActivityThread.-wrap11(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593) at android.os.Handler.dispatchMessage(Handler.java:105) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6541) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767) Caused by: java.lang.NullPointerException: Presenter returned from createPresenter() is null. Activity is com.mobile.myapp.ui.login.activities.AuthenticationActivity@8ba807c at com.hannesdorfmann.mosby3.mvp.delegate.ActivityMvpDelegateImpl.createViewIdAndCreatePresenter(ActivityMvpDelegateImpl.java:92) at com.hannesdorfmann.mosby3.mvp.delegate.ActivityMvpDelegateImpl.onCreate(ActivityMvpDelegateImpl.java:142) at com.hannesdorfmann.mosby3.mvp.MvpActivity.onCreate(MvpActivity.java:42) at com.mobile.myapp.ui.base.MyappBaseMvpActivity.onCreate(MyappBaseMvpActivity.java:88) at com.mobile.myapp.ui.login.activities.AuthenticationActivity.onCreate(AuthenticationActivity.java:56) at android.app.Activity.performCreate(Activity.java:6975) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892) at android.app.ActivityThread.-wrap11(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593) at android.os.Handler.dispatchMessage(Handler.java:105) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6541) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767) 12-22 08:58:10.863 1811-1823/system_process E/memtrack: Couldn't load memtrack module

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/sockeqwe/mosby/issues/298, or mute the thread https://github.com/notifications/unsubscribe-auth/AAjnriuP1IgcidmF-zwKwfHUeaxBEHASks5tC3LPgaJpZM4RK0GO .

j2emanue commented 6 years ago

ok. could you make it so that it accepts the presenter i am returning on onCreatePresenter ? I'll have to call this in all of our classes which is a huge task. Dagger2 does not work in base abstract classes. So each concrete class i'll have to override the getters/setters for the presenter. we never use to have to do this before , im wondering if you can change it to not do that ?

sockeqwe commented 6 years ago

Does getPresenter() and setPresenter() actually solves your problem?

j2emanue commented 6 years ago

so here is what i did:

@NonNull @Override public LandingPagePresenter createPresenter() { return presenter; //confirmed this is not null }

@Override
public void setPresenter(@NonNull LandingPagePresenter presenter_notused) {
    super.setPresenter(presenter); //confirmed neither presenter and presenter_notused are null (and they are the same )
}

i still unfortuantly, got the same error. which ill show below:

FATAL EXCEPTION: main Process: com.mobile.myapp.labs, PID: 8977 java.lang.NullPointerException: Presenter returned from createPresenter() is null. Activity is com.mobile.myapp.ui.landing.LandingPageActivity@252836b at com.hannesdorfmann.mosby3.mvp.delegate.FragmentMvpDelegateImpl.createViewIdAndCreatePresenter(FragmentMvpDelegateImpl.java:104) at com.hannesdorfmann.mosby3.mvp.delegate.FragmentMvpDelegateImpl.onCreate(FragmentMvpDelegateImpl.java:268) at com.hannesdorfmann.mosby3.mvp.MvpFragment.onCreate(MvpFragment.java:101) at android.support.v4.app.Fragment.performCreate(Fragment.java:2246) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1377) at android.support.v4.app.FragmentTransition.addToFirstInLastOut(FragmentTransition.java:1187) at android.support.v4.app.FragmentTransition.calculateFragments(FragmentTransition.java:1070) at android.support.v4.app.FragmentTransition.startTransitions(FragmentTransition.java:115) at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2374) at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2332) at android.support.v4.app.FragmentManagerImpl.execSingleAction(FragmentManager.java:2209) at android.support.v4.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:649) at android.support.v4.app.FragmentStatePagerAdapter.finishUpdate(FragmentStatePagerAdapter.java:167) at android.support.v4.view.ViewPager.populate(ViewPager.java:1238) at android.support.v4.view.ViewPager.populate(ViewPager.java:1086) at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1616) at android.view.View.measure(View.java:22002) at android.widget.LinearLayout.measureVertical(LinearLayout.java:958) at android.widget.LinearLayout.onMeasure(LinearLayout.java:685) at android.view.View.measure(View.java:22002) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6580) at android.support.design.widget.CoordinatorLayout.onMeasureChild(CoordinatorLayout.java:719) at android.support.design.widget.CoordinatorLayout.onMeasure(CoordinatorLayout.java:791) at android.view.View.measure(View.java:22002) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6580) at android.widget.FrameLayout.onMeasure(FrameLayout.java:185) at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:139) at android.view.View.measure(View.java:22002) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6580) at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1514) at android.widget.LinearLayout.measureVertical(LinearLayout.java:806) at android.widget.LinearLayout.onMeasure(LinearLayout.java:685) at android.view.View.measure(View.java:22002) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6580) at android.widget.FrameLayout.onMeasure(FrameLayout.java:185) at android.view.View.measure(View.java:22002) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6580) at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1514) at android.widget.LinearLayout.measureVertical(LinearLayout.java:806) at android.widget.LinearLayout.onMeasure(LinearLayout.java:685) at android.view.View.measure(View.java:22002) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6580) at android.widget.FrameLayout.onMeasure(FrameLayout.java:185) at com.android.internal.policy.DecorView.onMeasure(DecorView.java:721) at android.view.View.measure(View.java:22002) at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2410) at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1498) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1751) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1386) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6733) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:911) 12-22 11:30:01.985 8977-8977/com.mobile.myapp.labs E/AndroidRuntime: at android.view.Choreographer.doCallbacks(Choreographer.java:723) at android.view.Choreographer.doFrame(Choreographer.java:658) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897) at android.os.Handler.handleCallback(Handler.java:789) at android.os.Handler.dispatchMessage(Handler.java:98) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6541) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)

jshvarts commented 6 years ago

If Presenter is the only thing you inject into your View, you can have the Component expose it so you can inject the Presenter itself in createPresenter().

    override fun createPresenter() = DaggerSearchComponent.builder()
        .appComponent(GithubApp.component)
        .searchModule(SearchModule())
        .build()
        .presenter()

See example https://github.com/jshvarts/MosbyMVP/blob/master/conductor-dagger-sample/src/main/java/com/jshvarts/mosbymvp/searchrepos/SearchViewController.kt

Also, you don't need to include both mvp and viewstate Gradle dependency. The latter is sufficient.

sockeqwe commented 6 years ago

Yeah I definitely recommend to create the dependency graph in createPresenter() and have a component like this:

@Component
interface MyApplicationComponent {
   MyPresenter myPresenter();
}

Rather than

@Component
interface MyApplicationComponent {
   void inject(MyActivity activityWherePresenterGetsInjected);
}

Nevertheless, the way you would like to do it (inject presenter into activity) should also work if you override getPresenter() and setPresenter() to use your local variable.

j2emanue commented 6 years ago

My presenter constructor takes arguments. Dagger builds it for me

Get Outlook for Androidhttps://aka.ms/ghei36


From: James Shvarts notifications@github.com Sent: Friday, December 22, 2017 6:51:05 PM To: sockeqwe/mosby Cc: j2emanue; Author Subject: Re: [sockeqwe/mosby] Dagger2 - injecting presenter gives Caused by: java.lang.NullPointerException: Presenter returned from createPresenter() is null. Activity is ... (#298)

If Presenter is the only thing you inject into your View, you can have the object graph expose it and so you can inject the Presenter itself in createPresenter(). See example https://github.com/jshvarts/MosbyMVP/blob/master/conductor-dagger-sample/src/main/java/com/jshvarts/mosbymvp/searchrepos/SearchViewController.kt

Also, you don't need to include both mvp and viewstate Gradle dependency. The latter is sufficient.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHubhttps://github.com/sockeqwe/mosby/issues/298#issuecomment-353583474, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AEuvOvgU1xjroSxzeC9V_nkiinKnsEehks5tC5epgaJpZM4RK0GO.

sockeqwe commented 6 years ago

Sure, that is not changed. dagger still creates the presenter instance with all required dependencies (constructor parameters of presenter)

j2emanue notifications@github.com schrieb am Fr., 22. Dez. 2017, 13:14:

My presenter constructor takes arguments. Dagger builds it for me

Get Outlook for Androidhttps://aka.ms/ghei36


From: James Shvarts notifications@github.com Sent: Friday, December 22, 2017 6:51:05 PM To: sockeqwe/mosby Cc: j2emanue; Author Subject: Re: [sockeqwe/mosby] Dagger2 - injecting presenter gives Caused by: java.lang.NullPointerException: Presenter returned from createPresenter() is null. Activity is ... (#298)

If Presenter is the only thing you inject into your View, you can have the object graph expose it and so you can inject the Presenter itself in createPresenter(). See example https://github.com/jshvarts/MosbyMVP/blob/master/conductor-dagger-sample/src/main/java/com/jshvarts/mosbymvp/searchrepos/SearchViewController.kt

Also, you don't need to include both mvp and viewstate Gradle dependency. The latter is sufficient.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub< https://github.com/sockeqwe/mosby/issues/298#issuecomment-353583474>, or mute the thread< https://github.com/notifications/unsubscribe-auth/AEuvOvgU1xjroSxzeC9V_nkiinKnsEehks5tC5epgaJpZM4RK0GO

.

— You are receiving this because you commented.

Reply to this email directly, view it on GitHub https://github.com/sockeqwe/mosby/issues/298#issuecomment-353586695, or mute the thread https://github.com/notifications/unsubscribe-auth/AAjnrv2ePK0138kuD4zNS0-0G16cC3FSks5tC50OgaJpZM4RK0GO .

jshvarts commented 6 years ago

If you look at my example above, you will see that my Presenter gets instantiated by Dagger and it takes parameters via constructor injection.

j2emanue commented 6 years ago

I see no difference if I do this. I'm calling dagger inject before super.oncreate . Therefore my presenter already has a reference. I don't think createpresenter method is called before onCreate , right? I guess you guys changed the implementation a bit. How is exposing the method in the component bringing different results then annotating the presenter constructor with @Inject. I tried overriding set/getters as recommended but same issue.

sockeqwe commented 6 years ago

Is your source code available somewhere so that I can try to debug it? createPresenter() is called in super.onCreate() (see here )


I think either you or we are misunderstanding something, so here is a full example implementation what @jshvarts and I are talking about is the following one:

public class AuthenticationActivity extends MvpActivity<AuthenticationView, AuthenticationPresenter> implements AuthenticationView {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_authentication);
        ButterKnife.bind(this);
        presenter.loadScreen();  // presenter variable is a Mosby internal variable from MvpActivity
        //blah blah
    }

    @Override
    public AuthenticationPresenter createPresenter() {
        return    ((MyappApplication) getApplicationContext()).getAppComponent().authenticationPresenter();
    }
  }
@Singleton
class AuthenticationPresenter extend MvpBasePresenter<AuthenticationView> {

    @Inject
    public AuthenticationPresenter(UserManager userManager) { // Some dependencies passed as constructor parameter
        ...
    }
}
@Module
class AppModule {

    @Provides 
    @Singleton
    public UserManager provideUserManager() {
       ...
    } 
}
@Singleton
@Component(modules = {AppModule.class}
interface AppComponent {
    AuthenticationPresenter authenticationPresenter();
}

Please note that we are not manually instantiating AuthenticationPresenter nor specifying it in AppModule.

How is exposing the method in the component bringing different results then annotating the presenter constructor with @Inject.

You are not removing @Inject method from presenter constructor, this is still the same as you see in the cose snipped above. The difference is really just how you define your dagger component: instead of asking dagger to inject presenter into activity (via inject(AuthenticationActicity activity), you ask dagger to give you a presenter (by exposing a method like authenticationPresenter()).

The later is the recommended way for Mosby

j2emanue commented 6 years ago

here is what i have done:

My app component has the following declared:

LandingPagePresenter landingPagePresenter();

and in the landingPageActivity i took out the @Inject annotation so now the presenter declartion looks like this:

// @Inject LandingPagePresenter presenter;

here is the onCreate method:

@Override protected void onCreate(Bundle savedInstanceState) { ((MyApplication) getApplicationContext()).getAppComponent().inject(this); super.onCreate(savedInstanceState); presenter= getPresenter(); //now i am calling your getPresenter method but i also tried without this setContentView(R.layout.activity_homepage); //blah blah }

here is the createpresenter override:

@NonNull
    @Override
    public LandingPagePresenter createPresenter() {
//confirmed dagger did return a presenter here through debugger
       return ((MyApplication) getApplicationContext()).getAppComponent().landingPagePresenter();

    }

i also tried the following:

@NonNull @Override public LandingPagePresenter createPresenter() { //confirmed dagger did return a presenter here through debugger presenter= ((MyApplication) getApplicationContext()).getAppComponent().landingPagePresenter(); return presenter; }

here is the constructor signature for the presenter::

@Inject public LandingPagePresenter( GatewayFactory gatewayFactory, GetFeedsUsecase feedsUsecase, MySharedPrefRepo sharedPrefRepo) { //...blah blah }

i still get the same error:

E/AndroidRuntime: FATAL EXCEPTION: main Process: com.mobile.my.labs, PID: 5100 java.lang.NullPointerException: Presenter returned from createPresenter() is null. Activity is com.mobile.my.ui.landing.LandingPageActivity@b0c662e at com.hannesdorfmann.mosby3.mvp.delegate.FragmentMvpDelegateImpl.createViewIdAndCreatePresenter(FragmentMvpDelegateImpl.java:104) at com.hannesdorfmann.mosby3.mvp.delegate.FragmentMvpDelegateImpl.onCreate(FragmentMvpDelegateImpl.java:268) at com.hannesdorfmann.mosby3.mvp.MvpFragment.onCreate(MvpFragment.java:101) at android.support.v4.app.Fragment.performCreate(Fragment.java:2246) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1377) at android.support.v4.app.FragmentTransition.addToFirstInLastOut(FragmentTransition.java:1187) at android.support.v4.app.FragmentTransition.calculateFragments(FragmentTransition.java:1070) at android.support.v4.app.FragmentTransition.startTransitions(FragmentTransition.java:115) at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2374) at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2332) at android.support.v4.app.FragmentManagerImpl.execSingleAction(FragmentManager.java:2209) at android.support.v4.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:649) at android.support.v4.app.FragmentStatePagerAdapter.finishUpdate(FragmentStatePagerAdapter.java:167) at android.support.v4.view.ViewPager.populate(ViewPager.java:1238) at android.support.v4.view.ViewPager.populate(ViewPager.java:1086) at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1616) at android.view.View.measure(View.java:22002) at android.widget.LinearLayout.measureVertical(LinearLayout.java:958) at android.widget.LinearLayout.onMeasure(LinearLayout.java:685) at android.view.View.measure(View.java:22002) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6580)

in all cases above i have not overriden setPresenter or getPresenter. i guess i'll have to see if anyone else gets these errors and for now return to mosby2 unless you guys see something im not doing or missed .

jshvarts commented 6 years ago

I believe all you need to do is to have this done:

@Override
public LandingPagePresenter createPresenter() {
    return ((MyApplication) getApplicationContext()).getAppComponent().landingPagePresenter();
}

Do not have any Dagger code in the onCreate() and do not declare LandingPagePresenter presenterinstance variable in your Activity (View). Whenever you need to reference the Presenter in your Activity, just call presenter.foo()

j2emanue commented 6 years ago

I think I have to inject dagger dependencies from onCreate because I have other dependencies that need to be injected in not just a present. For example analytics manager etc.

Get Outlook for Androidhttps://aka.ms/ghei36


From: James Shvarts notifications@github.com Sent: Saturday, December 23, 2017 5:37:41 AM To: sockeqwe/mosby Cc: j2emanue; Author Subject: Re: [sockeqwe/mosby] Dagger2 - injecting presenter gives Caused by: java.lang.NullPointerException: Presenter returned from createPresenter() is null. Activity is ... (#298)

I believe all you need to do is to have this done:

@Override public LandingPagePresenter createPresenter() { return ((MyApplication) getApplicationContext()).getAppComponent().landingPagePresenter(); }

Do not have any Dagger code in the onCreate() and do not declare LandingPagePresenter presenter in your Activity (View). Whenever you need to reference the Presenter in your Activity, just call presenter.foo()

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHubhttps://github.com/sockeqwe/mosby/issues/298#issuecomment-353685378, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AEuvOkZVMrPt3SO03oTL-SsYYwuaD6e4ks5tDC81gaJpZM4RK0GO.

jshvarts commented 6 years ago

That's why I asked in my first reply above if the Presenter was the only one dependency that needs to be injected.

Something like this should work (I am converting it from Kotlin as I type):

In your Dagger Component:

void inject(LandingPageActivity activity);

In your LandingPageActivity:

@Inject
LandingPagePresenter myPresenter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    ((MyappApplication) getApplicationContext()).getAppComponent().inject(this);
    super.onCreate(savedInstanceState);
    ...
}

@Override
void setPresenter(LandingPagePresenter presenter) {
    this.presenter = presenter
}

@Override
LandingPagePresenter createPresenter() {
    return myPresenter;
}
j2emanue commented 6 years ago

jshvarts , i assume that you meant myPresenter variable in the setter and not this.presenter :

@Override
void setPresenter(LandingPagePresenter presenter) {
    this.myPresenter = presenter
}

i treied exactly as you put and i also tried it in another class just to make sure. its the same error. i have the code exactly how you wrote it. lets take a look more in depth at my code:

here is my activity:

`public class LandingPageActivity extends BaseMvpActivity<LandingPageView, LandingPagePresenter> implements LandingPageView {

        @Inject
    LandingPagePresenter presenter;

    @Inject
    ApplicationMode appMode;

    @Inject
    EventBus bus;

    @Override
    public void setPresenter(LandingPagePresenter presenter) {
        this.presenter = presenter;
    }

    @NonNull
    @Override
    public LandingPagePresenter createPresenter() {
        return this.presenter;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ((MyApplication) getApplicationContext()).getAppComponent().inject(this);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_homepage);
        ButterKnife.bind(this);
        initView();
    }

    }`

and here is the BaseActivity class definition:

public abstract class BaseMvpActivity<V extends BaseMvpView, P extends MvpPresenter<V>>
        extends MvpActivity<V, P>  {........}

and here is BaseMvpView:

public interface BaseMvpView extends MvpView {

    void showError(@StringRes int e);

    void showError(String msg);
//....blah blah
}

again the environment im running on is Oreo api 26 but i also tried it on api 23 emulator.
with dependency: implementation 'com.hannesdorfmann.mosby3:viewstate:3.1.0'

for completeness below is my dagger2 component:

@Singleton
@Component(modules = {AppModule.class, NetworkModule.class, ActivityModule.class})
public interface AppComponent {

    void inject(MyApplication target);

    void inject(LandingPageActivity target);

//......

}
sockeqwe commented 6 years ago

I have some time tomorrow after lunch. I will try to reproduce / debug your issue.

j2emanue notifications@github.com schrieb am Sa., 23. Dez. 2017, 07:08:

jshvarts , i assume that you meant myPresenter variable in the setter and not this.presenter :

@Override void setPresenter(LandingPagePresenter presenter) { this.myPresenter = presenter }

i treied exactly as you put and i also tried it in another class just to make sure. its the same error. i have the code exactly how you wrote it. lets take a look more in depth at my code:

here is my activity:

`public class LandingPageActivity extends BaseMvpActivity<LandingPageView, LandingPagePresenter> implements LandingPageView {

@Inject

LandingPagePresenter presenter;

@Inject ApplicationMode appMode;

@Inject EventBus bus;

@Override public void setPresenter(LandingPagePresenter presenter) { this.presenter = presenter; }

@NonNull @Override public LandingPagePresenter createPresenter() { return this.presenter; }

@Override protected void onCreate(Bundle savedInstanceState) { ((MyApplication) getApplicationContext()).getAppComponent().inject(this); super.onCreate(savedInstanceState); setContentView(R.layout.activity_homepage); ButterKnife.bind(this); initView(); }

}`

and here is the BaseActivity class definition:

public abstract class BaseMvpActivity<V extends BaseMvpView, P extends MvpPresenter> extends MvpActivity<V, P> {........}

and here is BaseMvpView:

public interface BaseMvpView extends MvpView {

void showError(@StringRes int e);

void showError(String msg);

//....blah blah }

again the environment im running on is Oreo api 26 but i also tried it on api 23 emulator. with dependency: implementation 'com.hannesdorfmann.mosby3:viewstate:3.1.0'

— You are receiving this because you commented.

Reply to this email directly, view it on GitHub https://github.com/sockeqwe/mosby/issues/298#issuecomment-353709462, or mute the thread https://github.com/notifications/unsubscribe-auth/AAjnrmfTkfCXaqou--sTvI1yd9pHVTSrks5tDJjsgaJpZM4RK0GO .

lebeshev commented 6 years ago

@j2emanue Hi! It's probably too late, but since an issue hasn't been closed I want to tell you about how I make dependency injection for mosby. I use MVI instead of MVP but it doesn't change a lot.

I have a LoginFragment class with corresponding LoginPresenter and LoginComponent. Code of LoginComponent:

@Subcomponent
public interface LoginComponent {

    @Subcomponent.Builder
    interface Builder {

        LoginComponent build();

    }

    void inject(LoginFragment loginFragment);

    // Important!
    LoginPresenter getLoginPresenter();

}

I have a separate class called Injection, where I handle lifecycle of all my components and subsomponents. It looks kinda like this:

public class Injection {

    private Injection() {
    }

    private static AppComponent appComponent;

    private static LoginComponent loginComponent;

    public static void init(Application application) {
        appComponent = DaggerAppComponent.builder()
                .application(application)
                .build();
    }

    public static LoginComponent inject(LoginFragment loginFragment) {
        loginComponent = appComponent.loginComponentBuilder().build();
        loginComponent.inject(loginFragment);
        return loginComponent;
    }

    public static void clear(LoginFragment loginFragment) {
        loginComponent = null;
    }

}

And here is how all this stuff is being used in LoginFragment:

class LoginFragment : MviFragment<LoginView, LoginPresenter>(), LoginView {

    private lateinit var loginComponent: LoginComponent

    override fun onCreate(savedInstanceState: Bundle?) {
        loginComponent = Injection.inject(this)
        super.onCreate(savedInstanceState)
    }

   // Other lifecycle methods

    override fun createPresenter(): LoginPresenter = loginComponent.loginPresenter

}

This way I can inject all my fragment's dependensies using members-injection (calling Injection.inject(this)) and get my presenter using provision method (the LoginPresenter getloginPresenter() one). You can read more about members-injection and provision methods in docs.

Using this method I get no runtime exceptions. Hope I helped!

j2emanue commented 5 years ago

do you guys want to set up a phone call or screen share so we can fix this issue ?

pawelnbd1992 commented 5 years ago

@j2emanue Did you fix this issue ?

leslieam commented 5 years ago

I've got the same issue. Using Dagger 2.16 and Mosby 3.1.0.

engi2nee commented 5 years ago

I had no problems injecting the presenter then setting it manually to the Mosby's internal presenter So in the activity:

@Inject lateinit var myPresenter: MyPresenter override fun createPresenter(): MyPresenter = myPresenter

MyPresenter uses dagger's constructor injecting of course