泛型类型和多态性

时间:2017-11-14 09:17:57

标签: android generics kotlin

我有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);
    }
}  

和许多扩展它的类。例如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);
        }
}   

我想避免重复每个片段和演示者的生命周期同步代码。因此,我想在BaseFragment中实现此过程。在Java中,这一行presenter.onAttachView(this);有效但警告“未经检查的呼叫onAttachView(V)”(我可以忍受这一点)。但 Kotlin 不允许我这样做

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"
    }

//...
}

我真的需要有关如何正确执行此操作的建议。

编辑:

    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) {

        }
}

以下是整个测试代码https://github.com/AlexNikolaTest/Test/tree/master/app/src/main/java/com/example/mytest

3 个答案:

答案 0 :(得分:5)

我认为将star-projection替换为BaseMvpView会有所帮助

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)
    }

//...
}

原因是Kotlin区分outin类型参数(也分别称为协变逆变参数类型)。

in类型参数声明类型参数将被泛型类消耗,即用作函数的参数,而out类型参数声明泛型类将生成传递类型的值 参数,即用作某些函数的返回类型。

onAttachView(V mvpView)采用逆变型参数,这意味着V不允许任何类型(它必须是BaseMvpView类型或子类),因为你消费该值。也就是说,如果V完全未知,我们无法安全地读取参数,因为V应该是BaseMvpView的实例。但是,如果是onAttachView 生成的情况,即。返回,V对象然后星形投影将起作用。

希望这有帮助!

答案 1 :(得分:3)

也许你可以这样做

interface IView

interface IPresenter {
    fun attachView(v: IView)
    fun detachView()
}

abstract class BasePresenter<V :IView> : IPresenter {
    protected var view: V? = null

    override fun attachView(v: IView) {
        this.view = v as V
    }

    override fun detachView() {
        view = null
    }
}

abstract class BaseFragment<P : IPresenter> : Fragment(), IView {
    protected lateinit var presenter: P

    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        presenter.attachView(this)
    }

    override fun onDestroyView() {
        super.onDestroyView()
        presenter.detachView()
    }
}

interface TestView : IView {
    fun doSomething()
}

interface TestPresenter : IPresenter {
    fun doSomething()
}

class TestPresenterImpl : BasePresenter<TestView>(), TestPresenter {
    override fun doSomething() {
    }
}

class TestFragment : BaseFragment<TestPresenter>(), TestView {

    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        presenter = TestPresenterImpl()
        presenter.doSomething()
    }

    override fun doSomething() {
    }
}

答案 2 :(得分:3)

你可以尝试这个,然后你也可以在Kotlin中获得未经检查的警告; - )

    if (presenter != null) {
        val p = presenter as BasePresenter<BaseMvpView>
        p.onAttachView(this)
    }

在您的MainFragment中

    syncLifeCycle(presenter as BasePresenter<BaseMvpView>)

不确定它是否有效,只是在IntelliJ中玩了一下。但是由于在编译期间擦除了泛型并且将MainPresenter转换为BasePresenter也应该没问题,因此它很有可能会通过。