Как иметь универсальный ViewModel в классе BaseActivty - PullRequest
0 голосов
/ 22 марта 2019

Я хочу иметь базовый класс активности, который заботится о некоторой инициализации, я начал определять его следующим образом.

abstract class BaseActivity<VIEW_MODEL : ViewModel, BINDING : ViewDataBinding> :
    AppCompatActivity() {
    lateinit var viewmodel: VIEW_MODEL
    lateinit var binding: BINDING

    lateinit var glide: RequestManager

    @get:LayoutRes
    abstract val layoutResource: Int


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = DataBindingUtil.setContentView(this, layoutResource)
        viewmodel = ViewModelProviders.of(this).get(VIEW_MODEL::class.java)
                                                    ^^^^^^^^^^^^^^^^^
                                                    this is causing error
    }
}

Но я получаю эту ошибку

Не могу использовать'VIEW_MODEL' как параметр типа reified.Вместо этого используйте класс

Как мне решить эту проблему, где я хочу определить тип ViewModel как типизированный параметр BaseActivity.

А как я могу его создать?

Ответы [ 3 ]

1 голос
/ 22 марта 2019

Одно из решений состоит в том, чтобы иметь что-то вроде этого

abstract val viewModelClass: Class<VIEW_MODEL>

Мне бы очень не хотелось, чтобы что-то подобное

0 голосов
/ 22 марта 2019

1-й способ Создайте метод abstarct в Base Activity. Таким образом, вы должны переопределить метод abstarct во всех действиях.

abstract class BaseActivity< ViewModel : BaseViewModel,Binding : ViewDataBinding> : AppCompatActivity(){
            protected lateinit var binding: Binding
            private var mViewModel: V? = null

        override fun onCreate(savedInstanceState: Bundle?) {
                super.onCreate(savedInstanceState)
                performViewModelBinding()
            }

            @LayoutRes
            abstract fun getLayoutResId(): Int

            abstract fun getViewModel(): ViewModel


    private fun performViewModelBinding() {
            binding = DataBindingUtil.setContentView(this, getLayoutResId())
            this.mViewModel = mViewModel ?: getViewModel()
            binding.setVariable(BR.viewModel, mViewModel)
            binding.executePendingBindings()
        }
    }

И когда вы переопределите этот метод вдеятельность

 override fun getViewModel(): MyProfileViewModel {
        mMyProfileViewModel = ViewModelProviders.of(this, mViewModelFactory).get(MyProfileViewModel::class.java)
        return mMyProfileViewModel
    }

2-й способ сделать это

abstract class BaseActivity<VIEW_MODEL : ViewModel, BINDING : ViewDataBinding> :
    AppCompatActivity() {
    lateinit var viewmodel: VIEW_MODEL
    lateinit var binding: BINDING

    lateinit var glide: RequestManager

    @get:LayoutRes
    abstract val layoutResource: Int


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = DataBindingUtil.setContentView(this, layoutResource)
        viewmodel = ViewModelProviders.of(this).get(getViewModelClass())

    }

private fun getViewModelClass(): Class<VIEW_MODEL> {
    val type = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0]          // index of 0 means first argument of BaseActivity class param
    return type as Class<VIEW_MODEL>
    }
}
0 голосов
/ 22 марта 2019

@ svkaka уже упомянул решение.Создайте абстрактный метод и переопределите его с вашим классом ViewModel:

protected abstract fun getViewModel(): Class<M>

Замените вашу строку на

viewmodel = ViewModelProviders.of(this).get(getViewModel())

Надеемся, это будет работать.

...