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