Как использовать Android-навигацию без привязки к пользовательскому интерфейсу в ViewModel (MVVM)?

Я использую навигацию для Android, которая была представлена ​​на Google I / O 2018, и кажется, что я могу использовать ее, привязав к некоторому представлению или используя NavHost, чтобы получить его из фрагмента. Но мне нужно перейти к другому конкретному представлению из ViewModel из моего первого фрагмента в зависимости от нескольких условий. Для ViewModel я расширяю AndroidViewModel, но не понимаю, что делать дальше. Я не могу преобразовать getApplication в Fragment / Activity и не могу использовать NavHostFragment. Также я не могу просто привязать навигацию к onClickListener, потому что startFragment содержит только один ImageView. Как мне перейти с ViewModel?

class CaptionViewModel(app: Application) : AndroidViewModel(app) {
private val dealerProfile = DealerProfile(getApplication())
val TAG = "REGDEB"


 fun start(){
    if (dealerProfile.getOperatorId().isEmpty()){
        if (dealerProfile.isFirstTimeLaunch()){
            Log.d(TAG, "First Time Launch")
            showTour()
        }else{
            showCodeFragment()
            Log.d(TAG, "Show Code Fragment")

        }
    }
}

private fun showCodeFragment(){
    //??
}

private fun showTour(){
    //??
}

}

Мой фрагмент

class CaptionFragment : Fragment() {
private lateinit var viewModel: CaptionViewModel
private val navController by lazy { NavHostFragment.findNavController(this) }

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
    viewModel = ViewModelProviders.of(this).get(CaptionViewModel::class.java)
    return inflater.inflate(R.layout.fragment_caption, container, false)
}


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

    viewModel.start()

}

}

Хочу сохранить логику навигации в ViewModel

Библиотека навигации - это в первую очередь компонент пользовательского интерфейса, вам необходимо сохранить логику пользовательского интерфейса в пользовательском интерфейсе, поэтому вам необходимо выполнить навигацию во фрагменте / действии.

Levi Moreira 07.06.2018 14:09

У меня там будет несколько бэкендов, и я буду знать, куда идти. Должен быть способ сделать это

Ekaterina Levchenko 07.06.2018 14:17

Затем вам нужно распространить эти параметры как состояние на пользовательский интерфейс и принять решение там. ViewModel не должен ничего знать о представлении, поэтому в соответствии с его архитектурой он просто передает данные некоторому представлению, которое будет подпадать под его данные. Возможно, вы ищете архитектуру, в которой ViewModel может активно изменять View. Это будет архитектура MVP, где докладчик может активно изменять представление

Levi Moreira 07.06.2018 14:21

Несмотря на то, что я пытался выполнить эту навигацию в классе Fragment, произошла ошибка FragmentManager is already executing transactions

Ekaterina Levchenko 07.06.2018 14:28

Я согласен со всем, что сказал @LeviAlbuquerque. Не видел вашего кода, но это может быть проблема, который будет исправлен в alpha02

Sander 07.06.2018 14:37
11
5
7 750
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

How can I navigate from ViewModel?

Ответ: пожалуйста, не надо. ViewModel предназначен для хранения данных, связанных с пользовательским интерфейсом, и управления ими.

Новый ответ

В своих предыдущих ответах я сказал, что нам не следует переходить из ViewModel, и причина в том, что для навигации ViewModel должен иметь ссылки на Activity / Fragments, которые, как я считаю (возможно, не самые лучшие, но все же я верю в это), никогда не хорошая идея.

Но в рекомендуемой архитектуре приложения от Google упоминается, что мы должен выводить пользовательский интерфейс из модели. И после того, как я подумаю, что они имеют в виду?

Итак, я проверил образец из "android-architecture" и нашел интересный способ, как это сделал Google.

Пожалуйста, проверьте здесь: todo-mvvm-привязка данных

Как оказалось, они действительно вывести пользовательский интерфейс из модели. Но как?

  1. Они создали интерфейс ЗадачиНавигатор, который, по сути, просто интерфейс навигации.
  2. Затем в ЗадачиViewModel у них есть эта ссылка на TaskNavigator, чтобы они могли управлять пользовательским интерфейсом, не имея прямой ссылки на действия / фрагменты.
  3. Наконец, TasksActivity реализовал TasksNavigator для предоставления подробных сведений о каждом действии навигации, а затем установил для навигатора значение TasksViewModel.

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

EpicPandaForce 07.06.2018 19:51

Я не сказал, что это ответственность View. Но ViewModel также не несет ответственности за это. Навигация по ViewModel никогда не бывает хорошей идеей.

Yosi Pramajaya 08.06.2018 03:10

Я думаю, вы должны хотя бы объяснить, почему это «никогда не бывает хорошей идеей».

Neal Sanche 01.10.2018 05:16

ViewModel - это подходящее место для навигации, просто в Android это становится проблемой, потому что нам нужен доступ к представлению для выполнения этой навигации. Также нет хорошего способа абстрактной навигации. Итак, вообще говоря, навигацию с виртуальной машины на Android не так просто выполнить, но на других платформах это возможно.

Glaucus 02.10.2018 18:59

Я отредактировал ответы, и, надеюсь, вы понимаете.

Yosi Pramajaya 03.10.2018 02:50

Просто ради интереса, мне больше нравится текущий ответ Йози. Мы использовали Cicerone, и у него есть объект Router, который предоставляет доступ для выполнения навигации из ViewModel, и это работает довольно хорошо. Возможно, в какой-то момент мне придется посмотреть, что потребуется для интеграции Цицерона с компонентом навигации.

Neal Sanche 10.10.2018 18:18

Я могу ошибаться или опаздывать, но разве эта стратегия не передает ссылку на представление модели представления? что могло привести к утечке памяти

jack_the_beast 22.09.2020 15:01

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