Android компонент навигации: Как получить идентификатор текущего графика навигации? - PullRequest
1 голос
/ 11 января 2020

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

У меня также есть класс BaseFragment, который получает ссылку на требуемую модель представления:

fun provideViewModel() : VM {
        return if(viewModelScopeGraphId != null) {
            ViewModelProvider(findNavController().getViewModelStoreOwner(viewModelScopeGraphId!!)).get(viewModelClass)
        } else {
            ViewModelProvider(this).get(viewModelClass)
        }
     }

Я могу переопределить свойство, viewModelScopeGraphId, если мне нужна область видимости для определения области навигации (или вложенного графика навигации) с указанным c идентификатором. В идеале я бы просто хотел установить логический флаг типа useScopedViewModel и получить идентификатор текущего графика навигации, например:

fun provideViewModel() : VM {
        return if(useScopedViewModel) {
            ViewModelProvider(findNavController().getViewModelStoreOwner(getCurrentNavGraphId())).get(viewModelClass)
        } else {
            ViewModelProvider(this).get(viewModelClass)
        }
     }

Я пытался использовать navController.graph.id, чтобы получить идентификатор текущего графика, но кажется, что идентификатор, который я получаю оттуда, не совпадает с идентификатором моего ресурса (например, R.id.nav_graph). Что-то мне не хватает?

1 Ответ

1 голос
/ 23 марта 2020

У меня похожая проблема (больше контекста моего случая в конце), попробовал несколько решений, но ни одно из них не удалось.

В конце я сдаюсь и просто даю идентификатор графика в качестве параметра для фрагмент.

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

  • Необходимо создать это расширение, как только оригинал navGraphViewModels принимает @IdRes navGraphId: Int и я хочу лениво загрузить аргументы и т. д. c. (Также я упростил удаление factoryProducer из аргументов, так как пока я не буду использовать его для нашего решения.
inline fun <reified VM : ViewModel> Fragment.navGraphViewModels(
        noinline graphIdProducer: () -> Int
): Lazy<VM> {
    val backStackEntry by lazy {
        findNavController().getBackStackEntry(graphIdProducer())
    }
    val storeProducer: () -> ViewModelStore = {
        backStackEntry.viewModelStore
    }
    return createViewModelLazy(VM::class, storeProducer, {
        backStackEntry.defaultViewModelProviderFactory
    })
}
  • В моем фрагменте, где я хочу использовать это, я восстанавливаю Аргументы, используя navArgs, и восстанавливаю ViewModel, используя приведенное выше расширение:
    private val listenerViewModel: ListenerViewModel by navGraphViewModels {
        navArgs.graphId
    }

    private val navArgs: MyFragmentArgs by navArgs()
  • И тому, кому нужно "слушать" для этого ViewModel, можно просто загрузить с помощью Навигации navGraphViewModels:
    private val listenerViewModel: ListenerViewModel by navGraphViewModels(
            R.id.my_graph_a
    )    
  • И из другого графика / фрагмента я просто делаю:
    private val listenerViewModel: ListenerViewModel by navGraphViewModels(
            R.id.my_graph_b
    )    

К немного объясните контекст моего случая:

  • У меня есть два отдельных фрагмента, где пользователь может щелкнуть по выбору страны.
    • Каждый из этих фрагментов находится внутри другого графика, поскольку они представляют собой разные потоки.
  • Выбор страны - это фрагмент, в который загружается список поддерживаемых стран из API, отображается его, предварительно выбирается любой предыдущий выбор пользователя (также задается как FragmentArgs ), и пользователь может изменить выбор, что подразумевает приход вернуться к предыдущему экрану с новым выбранным значением или просто вернуться, не вызывая здесь ничего.
  • Я знаю и ожидаю выхода https://issuetracker.google.com/issues/79672220, но как сегодня (Март-2020) доступно только в alpha.
...