问题 泛型类型和多态性


我有 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)“(我可以忍受这个)。但是 科特林 根本不允许我这样做

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


3498
2017-11-14 09:17


起源

你能表现出来吗? onAttachView 主持人的方法? - OsipXD


答案:


我想更换 明星投影 同 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区分了 out 和 in 类型参数(也称为 协变 和 逆变 参数类型,分别)。

in type参数说明类型参数是什么 消费 通用类,即用作函数的参数,而 out 类型参数声明泛型类将 生产 传递类型的值 参数,即用作某些函数的返回类型。

onAttachView(V mvpView) 采用逆变类型参数,这意味着它不被允许 V 任何类型(必须是类型) BaseMvpView 或者是子类)因为你是 消费 那个价值。也就是说,如果 V 完全未知,我们无法安全地读取参数 V 预计将是一个实例 BaseMvpView。但是,如果是这样的话 onAttachView 是 生产 ,即。返回时, V 物体,然后星形投影将工作。

希望这可以帮助!


5
2017-11-22 22:26



在这种情况下,我无法从MainFragment调用方法syncLifeCycle(presenter)(泛型类型MainMvpView无法强制转换为BaseMvpView) - Alex Nik


也许你可以这样做

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

3
2017-11-16 10:58



我想在基本演示者中附加视图 - Alex Nik
对不起@AlexNik,我想我会跳过你问题的一些观点。所以我只是编辑了我的答案。我删除了一些部分,只包括 attatchView 和 detachView 因为我认为这两种方法对你最感兴趣。 - Khairil Ushan
嗨@AlexNik只是好奇,我的更新答案对你有帮助吗? :d - Khairil Ushan
一点点,谢谢 - Alex Nik


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

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

在您的MainFragment中

    syncLifeCycle(presenter as BasePresenter<BaseMvpView>)

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


3
2017-11-22 21:03