Я реализовал фрагмент, который изначально реализовал android.arch.lifecycle.Observer, и я хотел начать наблюдение за некоторыми другими данными в реальном времени, но не могу. Я начал с этого:
class MyFragment : BaseFragment(), Observer<FragmentData> {
lateinit var viewModel: MyViewModel
override fun onActivityCreated(savedInstanceState: Bundle?) {
viewModel.fragmentData.observe(this, this)
}
override fun onChanged(data: FragmentData?) {
activity?.title = getTitleFromData(data)
}
}
Если я обновлю класс, чтобы включить другие наблюдаемые данные, например:
class MyFragment : BaseFragment(), Observer<FragmentData>, Observer<OtherData> {
lateinit var viewModel: MyViewModel
override fun onActivityCreated(savedInstanceState: Bundle?) {
viewModel.fragmentData.observe(this, this)
}
override fun onChanged(otherData: OtherData) {
// update UI from otherData
}
override fun onChanged(data: FragmentData?) {
activity?.title = getTitleFromData(data)
}
}
Я получаю сообщение об ошибке:
Type parameter T of 'Observer' has inconsistent values: FragmentData, OtherData A supertype appears twice
Я хотел бы немного помочь понять, почему компилятор не может различить различия между типами и задавался вопросом о лучшем альтернативном шаблоне.
что-то вроде этого?:
viewModel.fragmentData.observe(this, fragmentDataObserver)
private val fragmentDataObserver = Observer<Fragmentdata> {
activity?.title = getTitleFromData(it)
}
Когда данные изменяются для тех двух Observable, которые я хочу разделить, выполняется значительный объем работы. Мне не нравится идея втиснуть все это в onActivityCreated ()
Итак, пусть ваша лямбда вызовет другую функцию, которая выполняет основную часть работы. Или используйте ссылку на функцию: stackoverflow.com/a/32600222/115145. Ваша попытка дважды реализовать интерфейс с использованием отдельных универсальных шаблонов также терпит неудачу в Java: public class Scrap implements Observer<String>, Observer<Boolean> приводит к синтаксической ошибке «дублированный класс».
Компилятор не может различить типы из-за стирания типа. Когда ваша программа компилируется, практически вся общая информация удаляется из классов. Observer<FragmentData> и Observer<OtherData> больше нет, есть только один класс Observer. Теперь, без стирания типа, было бы разумно, чтобы такие вещи были возможны
class MyFragment : BaseFragment(), Observer<FragmentData>, Observer<OtherData> {
override fun onChanged(otherData: OtherData) {
// update UI from otherData
}
override fun onChanged(data: FragmentData?) {
activity?.title = getTitleFromData(data)
}
}
но как только вы примените стирание типа, вы в основном пытаетесь дважды расширить один и тот же класс и предоставить два разных метода переопределения для одного и того же базового метода, что недопустимо. Вот почему компилятор не позволит вам это сделать. Это самое точное описание, которое я могу дать с моими ограниченными знаниями.
Что касается альтернативы, как предложено в комментариях, попробуйте использовать лямбда вместо того, чтобы пытаться сделать сам фрагмент двойным наблюдателем.
class MyFragment : BaseFragment(), Observer<OtherData> {
lateinit var viewModel: MyViewModel
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel.fragmentData.observe(this, Observer { onChanged(it) })
}
override fun onChanged(otherData: OtherData?) {
// update UI from otherData
}
private fun onChanged(data: FragmentData?) {
activity?.title = getTitleFromData(data)
}
}
Вы можете попробовать реализовать общий интерфейс Observer следующим образом:
class MyFragment : BaseFragment(), Observer<Any> {...}
а затем используйте метод onChanged
override fun onChanged(any: Any?) {
when:
any is isOtherData -> Do OtherData things
any is FragmentData -> Do FragmentData things
}
Второй обходной путь - создать родительский класс для OtherData и FragmentData, FatherInterface - это просто интерфейс, в теле которого ничего нет:
interface OtherData: FatherInterface{}...
interface FragmentData : FatherInterface{}...
Тогда ты можешь сделать
class MyFragment : BaseFragment(), Observer<FatherInterface>{}...
override fun onChanged(fatherInterface: FatherInterface?) {
when{
fatherInterface is OtherData -> ...
fatherInterface is FragmentData -> ...
}
// update UI from otherData
}
Вы должны иметь возможность просто использовать лямбда для вашего
Observer.