I have BaseFragment:
    public abstract class BaseFragment extends Fragment implements BaseMvpView {
        private BasePresenter presenter;
        protected void syncLifeCycle(BasePresenter presenter) {
            this.presenter = presenter;
            this.presenter.onCreate();
        }
        @Override
        public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            //noinspection unchecked
            presenter.onAttachView(this); //it works with a warning
        }
        @Override
        public void onResume() {
            super.onResume();
            presenter.onResume();
        }
        @Override
        public void onPause() {
            super.onPause();
            presenter.onPause();
        }
        @Override
        public void onDestroyView() {
            super.onDestroyView();
            presenter.onDetachView();
        }
        @Override
        public void onDestroy() {
            super.onDestroy();
            presenter.onDestroy();
        }
        @Override
        public void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            presenter.onActivityResult(requestCode, resultCode, data);
    }
}  
and many classes that extends it. For example MainFragment:
    public class MainFragment extends BaseFragment implements MainMvpView {
        MainPresenter<MainMvpView> presenter;
        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            syncLifeCycle(presenter);
            //presenter.onCreate();
        }
        @Override
        public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            //presenter.onAttachView(this);
        }
        @Override
        public void onResume() {
            super.onResume();
            //presenter.onResume();
        }
        @Override
        public void onPause() {
            super.onPause();
            //presenter.onPause();
        }
        @Override
        public void onDestroyView() {
            super.onDestroyView();
            //presenter.onDetachView();
        }
        @Override
        public void onDestroy() {
            super.onDestroy();
            //presenter.onDestroy();
        }
        @Override
        public void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            //presenter.onActivityResult(requestCode, resultCode, data);
        }
}   
I want to avoid repeating the life cycle synchronization code of each fragment and presenter. Therefore I want to implement this process in the BaseFragment. In Java this line presenter.onAttachView(this); works but with a warning "Unchecked call onAttachView(V)"(I can live with this). But Kotlin does not allow me to do this at all
abstract class BaseFragmentKotlin : Fragment(), BaseMvpView {
    private var presenter: BasePresenter<*>? = null
    //...
    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        presenter?.onAttachView(this) //Does not work. "Out-projected type 'BasePresenter<*>?' prohibits the use of 'public abstract fun onAttachView(mvpView: V!): Unit defined in com.example.test.BasePresenter"
    }
//...
}
I really need advice on how to do this correctly.
Edited:
    public class BasePresenterImpl<V extends BaseMvpView> implements BasePresenter<V> {
        @Nullable
        public V mvpView;
        @Override
        public void onCreate() {
        }
        @Override
        public void onAttachView(V mvpView) {
            this.mvpView = mvpView;
        }
        @Override
        public void onResume() {
        }
        @Override
        public void onPause() {
        }
        @Override
        public void onDetachView() {
        mvpView = null;
        }
        @Override
        public void onDestroy() {
        }
        @Override
        public void onActivityResult(int requestCode, int resultCode, Intent data) {
        }
}
Here is the whole test code https://github.com/AlexNikolaTest/Test/tree/master/app/src/main/java/com/example/mytest
You could try this, then you can have the unchecked warning in Kotlin as well ;-)
    if (presenter != null) {
        val p = presenter as BasePresenter<BaseMvpView>
        p.onAttachView(this)
    }
In your MainFragment
    syncLifeCycle(presenter as BasePresenter<BaseMvpView>)
Not sure if it works, just played around a bit in IntelliJ. But since generics are erased during compilation and casting a MainPresenter to BasePresenter should also be fine, there is a good chance it goes through.
I think replacing the star-projection with BaseMvpView would help
abstract class BaseFragmentKotlin : Fragment(), BaseMvpView {
    private var presenter: BasePresenter<BaseMvpView>? = null
    //...
    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        presenter?.onAttachView(this)
    }
//...
}
The reason is that Kotlin distinguishes between out and in type parameters (also known as covariant and contravariant parameter types, respectively).
in type parameters state that the type parameter is to be consumed by the generic class, i.e. to be used as a parameter of a function, while out type parameters state that the generic class will produce a value of passed type 
parameter, i.e. to be used as a return type for some function. 
the onAttachView(V mvpView) takes a contravariant type parameter which implies that it is not allowed for V to be of any type (it has to be of type BaseMvpView or a subclass) since you are consuming that value. That is, if V was totally unknown, we cannot safely read the parameter since V is expected to be an instance of BaseMvpView. However, if it were the case that onAttachView is producing ,i.e. returning, V object then star-projection would work.
Hope this helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With