Иметь класс, реализующий несколько наблюдателей

Я реализовал фрагмент, который изначально реализовал 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)
}

Вы должны иметь возможность просто использовать лямбда для вашего Observer.

CommonsWare 07.07.2018 22:35

Когда данные изменяются для тех двух Observable, которые я хочу разделить, выполняется значительный объем работы. Мне не нравится идея втиснуть все это в onActivityCreated ()

Jeff 07.07.2018 22:37

Итак, пусть ваша лямбда вызовет другую функцию, которая выполняет основную часть работы. Или используйте ссылку на функцию: stackoverflow.com/a/32600222/115145. Ваша попытка дважды реализовать интерфейс с использованием отдельных универсальных шаблонов также терпит неудачу в Java: public class Scrap implements Observer<String>, Observer<Boolean> приводит к синтаксической ошибке «дублированный класс».

CommonsWare 07.07.2018 22:48
3
3
693
2

Ответы 2

Компилятор не может различить типы из-за стирания типа. Когда ваша программа компилируется, практически вся общая информация удаляется из классов. 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
}

Другие вопросы по теме