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

In Activity method onCreate() is not call #285

Closed alexei-28 closed 6 years ago

alexei-28 commented 6 years ago

app/build.gradle:

apply plugin: 'com.android.application'
apply plugin: 'io.fabric'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'

dependencies {
...
implementation 'com.hannesdorfmann.mosby3:mvi:3.1.0'
    implementation 'com.hannesdorfmann.mosby3:mvp:3.1.0'
    implementation 'com.hannesdorfmann.mosby3:viewstate:3.1.0'
implementation 'com.hannesdorfmann.mosby3:mvp-lce:3.1.0'

}

Here my activity:

import com.hannesdorfmann.mosby3.mvp.MvpActivity;
    public class OfferDetailsPdfActivity extends MvpActivity<OfferDetailsPdfMvp.View, OfferDetailsPdfPresenterImplMvp> implements OnPageChangeListener, OfferDetailsPdfMvp.View {

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    }
    }

And method onCreate()success call.

But I need to pass param to activity, so here production code:

public class OfferDetailsPdfActivity extends MvpActivity<OfferDetailsPdfMvp.View, OfferDetailsPdfPresenterImplMvp> implements OnPageChangeListener, OfferDetailsPdfMvp.View {
private OfferDetailsPdfPresenterImplMvp presenter;
    private int offerId;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bundle extras = getIntent().getExtras();
        Debug.d(TAG, "onCreate: extras = " + AndroidUtil.bundle2String(extras)
                + "\nsavedInstanceState = " + AndroidUtil.bundle2String(savedInstanceState)
        );
        if (extras != null) {
            offerId = extras.getInt(Offer.ID);
        }
            setContentView(R.layout.offer_details_pdf);
        ButterKnife.bind(this);
    }

    @NonNull
    @Override
    public OfferDetailsPdfPresenterImplMvp createPresenter() {
        Debug.d(TAG, "createPresenter: offerId = " + offerId);
        presenter = new OfferDetailsPdfPresenterImplMvp(this, offerId);
        return presenter;
    }

And now in my activity method onCreate()is not call, but method createPresenter()was success called. Has text "createPresenter: offerId = 0"

As you can see from logcat the method onCreate() was not called. In logcat no text "onCreate: extras..."

Why?

Here logcat:

D/com.myproject.android.customer.ui.OfferDetailsPdfActivity(  946): createPresenter: offerId = 0
        Process: com.myproject.android.customer.debug, PID: 30127
       java.lang.RuntimeException: Unable to start activity ComponentInfo{com.myproject.android.customer.debug/com.myproject.android.customer.ui.OfferDetailsPdfActivity}: java.lang.IllegalArgumentException: Null objects cannot be copied from Realm.
           at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
           at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
           at android.app.ActivityThread.-wrap11(ActivityThread.java)
           at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
           at android.os.Handler.dispatchMessage(Handler.java:102)
           at android.os.Looper.loop(Looper.java:148)
           at android.app.ActivityThread.main(ActivityThread.java:5417)
           at java.lang.reflect.Method.invoke(Native Method)
           at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
           at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
        Caused by: java.lang.IllegalArgumentException: Null objects cannot be copied from Realm.
           at io.realm.Realm.checkValidObjectForDetach(Realm.java:1625)
           at io.realm.Realm.copyFromRealm(Realm.java:1318)
           at io.realm.Realm.copyFromRealm(Realm.java:1292)
           at com.myproject.android.customer.service.OfferService.getOffer(OfferService.java:54)
           at com.myproject.android.customer.mvp.presenter.OfferDetailsPdfPresenterImplMvp.loadData(OfferDetailsPdfPresenterImplMvp.java:64)
           at com.myproject.android.customer.mvp.presenter.OfferDetailsPdfPresenterImplMvp.<init>(OfferDetailsPdfPresenterImplMvp.java:59)
           at com.myproject.android.customer.ui.OfferDetailsPdfActivity.createPresenter(OfferDetailsPdfActivity.java:76)
           at com.myproject.android.customer.ui.OfferDetailsPdfActivity.createPresenter(OfferDetailsPdfActivity.java:35)
           at com.hannesdorfmann.mosby3.mvp.delegate.ActivityMvpDelegateImpl.createViewIdAndCreatePresenter(ActivityMvpDelegateImpl.java:90)
           at com.hannesdorfmann.mosby3.mvp.delegate.ActivityMvpDelegateImpl.onCreate(ActivityMvpDelegateImpl.java:142)
           at com.hannesdorfmann.mosby3.mvp.MvpActivity.onCreate(MvpActivity.java:42)
           at com.myproject.android.customer.ui.OfferDetailsPdfActivity.onCreate(OfferDetailsPdfActivity.java:58)
           at android.app.Activity.performCreate(Activity.java:6251)
           at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
           at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
           at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) 
           at android.app.ActivityThread.-wrap11(ActivityThread.java) 
           at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) 
           at android.os.Handler.dispatchMessage(Handler.java:102) 
           at android.os.Looper.loop(Looper.java:148) 
           at android.app.ActivityThread.main(ActivityThread.java:5417) 
           at java.lang.reflect.Method.invoke(Native Method) 
           at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
           at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 
sockeqwe commented 6 years ago

Hey, createPresenter() is called from onCreate(). So you basically have to call super.onCreate() after you have read the bundle like this:

public class OfferDetailsPdfActivity extends MvpActivity<OfferDetailsPdfMvp.View, OfferDetailsPdfPresenterImplMvp> implements OnPageChangeListener, OfferDetailsPdfMvp.View {
private OfferDetailsPdfPresenterImplMvp presenter;
    private int offerId;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Bundle extras = getIntent().getExtras();
        Debug.d(TAG, "onCreate: extras = " + AndroidUtil.bundle2String(extras)
                + "\nsavedInstanceState = " + AndroidUtil.bundle2String(savedInstanceState)
        );
        if (extras != null) {
            offerId = extras.getInt(Offer.ID);
        }

           super.onCreate(savedInstanceState);

            setContentView(R.layout.offer_details_pdf);
        ButterKnife.bind(this);
    }

    @NonNull
    @Override
    public OfferDetailsPdfPresenterImplMvp createPresenter() {
        Debug.d(TAG, "createPresenter: offerId = " + offerId);
        presenter = new OfferDetailsPdfPresenterImplMvp(this, offerId);
        return presenter;
    }

Im really sorry about that. It has some historical reasons and I don't want to break backward compatibility. Sorry.

Let me know if that fixes your problem.

alexei-28 commented 6 years ago

Yes, it's help. And now is work.

But... it's not very convenient. I MUST remember that if Activity have incoming params(extras) I MUST call onCreate() after read this paramas(extras). I hope you fix this in the future version.

Thanks.

sockeqwe commented 6 years ago

Most likely it will never be fixed as it would break backward compatibility. Also I don't consider this as a bug.

The problem is the following:

public FooActivity extends MvpActivity<FooView, FooPresenter> {
     @Override
    protected void onCreate(Bundle bundle) {
         super.onCreate(bundle);    // if we don't create the presenter in super.onCreate()
         presenter.loadFoo();      // you can't use presenter here because presenter is null
    }
}

So if we move createPresenter() to something like onStart() (which happens after onCreate()) you can't use the presenter in onCreate() so your code would look like this:

public FooActivity extends MvpActivity<FooView, FooPresenter> {

     private int someId;

     @Override
    protected void onCreate(Bundle bundle) {
         super.onCreate(bundle); // doesn't create presenter
         if (bundle != null) 
              someId = bundle.getInt("SomeKey");
    }

     @Override   
     protected void onStart() {
       super.onStart();           // creates the presenter
       presenter.loadFoo();      // now you can use the presenter
    }
}